├── webapp ├── readme.md ├── styles.css ├── index.html └── code.js ├── markdownapp ├── package.json ├── docservertomarkdown.js └── source.opml ├── docs ├── pages │ ├── webBrowser.md │ ├── speaker.md │ ├── clock.md │ ├── base64.md │ ├── dns.md │ ├── dialog.md │ ├── rss.md │ ├── drummer.md │ ├── oldSchool.md │ ├── tab.md │ ├── http.md │ ├── date.md │ ├── daytona.md │ ├── file.md │ ├── opml.md │ ├── github.md │ ├── op.md │ └── string.md └── readme.md └── readme.md /webapp/readme.md: -------------------------------------------------------------------------------- 1 | # DocServer 2 | 3 | Browse scripting verbs in a web app. 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /markdownapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docservertomarkdown", 3 | "version": "0.4.2", 4 | "author": "Dave Winer ", 5 | "main": "docservertomarkdown.js", 6 | "dependencies" : { 7 | "daveutils": "*", 8 | "request": "*", 9 | "davegithub": "*", 10 | "opml": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /docs/pages/webBrowser.md: -------------------------------------------------------------------------------- 1 | 2 | # webBrowser verbs 3 | ## webBrowser.openUrl 4 | #### Syntax 5 | webBrowser.openUrl (string) 6 | 7 | #### Params 8 | The string is a web address. 9 | 10 | #### What it does 11 | Opens the web page in a new browser tab or window. 12 | 13 | #### Returns 14 | true. 15 | 16 | #### Example 17 | `webBrowser.openUrl ("http://scripting.com/") ` 18 | 19 | - *true* 20 | 21 | -------------------------------------------------------------------------------- /docs/pages/speaker.md: -------------------------------------------------------------------------------- 1 | 2 | # speaker verbs 3 | ## speaker.beep 4 | #### Syntax 5 | speaker.beep () 6 | 7 | #### What it does 8 | Makes a standard beep sound on the computer's speaker. 9 | 10 | #### Notes 11 | It's useful for confirming an operation was done, or otherwise to attract the user's attention. 12 | 13 | #### Returns 14 | undefined 15 | 16 | #### Example 17 | `speaker.beep () === undefined` 18 | 19 | - *true* 20 | 21 | -------------------------------------------------------------------------------- /docs/pages/clock.md: -------------------------------------------------------------------------------- 1 | 2 | # clock verbs 3 | ## clock.now 4 | #### Syntax 5 | clock.now () 6 | 7 | #### Returns 8 | A JavaScript date object with the current date and time. 9 | 10 | #### Example 11 | `clock.now ()` 12 | 13 | - *Tue Mar 16 2021 14:31:39 GMT-0400 (Eastern Daylight Time)* 14 | 15 | ## clock.waitSeconds 16 | #### Syntax 17 | clock.waitSeconds (number) 18 | 19 | #### Parameters 20 | The number is the number of seconds it waits. It doesn't have to be a whole number (integer). 21 | 22 | #### Returns 23 | The number of seconds it waited. 24 | 25 | #### Notes 26 | The waiting is done via a JavaScript setTimeout call. 27 | 28 | #### Examples 29 | `clock.waitSeconds (1)` 30 | 31 | - *1.005* 32 | 33 | `clock.waitSeconds (1.3)` 34 | 35 | - *1.3* 36 | 37 | `clock.waitSeconds (random (1, 3))` 38 | 39 | - *2.005* 40 | 41 | -------------------------------------------------------------------------------- /docs/pages/base64.md: -------------------------------------------------------------------------------- 1 | 2 | # base64 verbs 3 | ## base64.encode 4 | #### Syntax 5 | base64.encode (string) 6 | 7 | #### Params 8 | The string is some text or data that you want to encode using the base64 algorithm. 9 | 10 | #### Returns 11 | The base64 encoding of the string. 12 | 13 | #### Example 14 | `base64.encode ("Hello Dolly")` 15 | 16 | - *SGVsbG8gRG9sbHk=* 17 | 18 | ## base64.decode 19 | #### Syntax 20 | base64.decode (string) 21 | 22 | #### Params 23 | The string is base64-encoded text. 24 | 25 | #### Returns 26 | The string that's decoded from the base64 encoded text. 27 | 28 | #### Example 29 | `base64.decode ("SGVsbG8gRG9sbHk=")` 30 | 31 | - *Hello Dolly* 32 | 33 | `base64.decode (base64.encode ("It's a wonderful day in the neighborhood."))` 34 | 35 | - *It's a wonderful day in the neighborhood.* 36 | 37 | -------------------------------------------------------------------------------- /docs/pages/dns.md: -------------------------------------------------------------------------------- 1 | 2 | # dns verbs 3 | ## dns.getDomainName 4 | #### Syntax 5 | dns.getDomainName (dottedid) 6 | 7 | #### Returns 8 | The domain name associated with the dotted id. This is often referred to as "reverse DNS." 9 | 10 | #### Common error 11 | There is no domain associated with the provided dotted id. 12 | 13 | #### Example 14 | `dns.getDomainName ("52.217.74.35") ` 15 | 16 | - *s3-website-us-east-1.amazonaws.com* 17 | 18 | #### Limits 19 | It only returns one domain name, but there might be more than one domain mapped to a given IP address. 20 | 21 | ## dns.getDottedId 22 | #### Syntax 23 | dns.getDottedId (name) 24 | 25 | #### Returns 26 | Return the dotted id associated with the name. This is often referred to as "DNS lookup." 27 | 28 | #### Common error 29 | The domain is not defined. 30 | 31 | #### Bug 32 | When there's an error, the error message is undefined. 33 | 34 | #### Example 35 | `dns.getDottedId ("scripting.com")` 36 | 37 | - *52.217.103.83* 38 | 39 | `dns.getDottedId ("feedbase.io")` 40 | 41 | - *157.230.11.43* 42 | 43 | `dns.getDottedId ("asdfasdf.wtf")` 44 | 45 | - *208.113.174.22* 46 | 47 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # DocServer 2 | 3 | The source release of the DocServer web app, a Node app that generates Markdown pages for the verb apps, and the Markdown pages the app generates. 4 | 5 | ### Links to various stuff 6 | 7 | 1. The deployed version of the web app. 8 | 9 | 4. The source for the web app. 10 | 11 | 2. The Markdown pages with a list of all the Drummer verbs. 12 | 13 | 3. The Node app that generates the Markdown files from the outlines. 14 | 15 | 5. Questions, comments? Post an item in this thread. 16 | 17 | ### This is an OPML application 18 | 19 | If you have an outliner that can emit OPML, you can create and maintain a set of man-pages in Markdown, as I am doing with Drummer and the docs for the built-in verbs in its scripting language. 20 | 21 | You can also browse the same outline in a web app with a GUI-style interface., 22 | 23 | Each approach has its advantages. :smile: 24 | 25 | Dave Winer, January 2022 26 | 27 | -------------------------------------------------------------------------------- /docs/pages/dialog.md: -------------------------------------------------------------------------------- 1 | 2 | # dialog verbs 3 | ## dialog.alert 4 | #### Syntax 5 | dialog.alert (string) 6 | 7 | #### Params 8 | The string is displayed in a dialog with a single button, OK. 9 | 10 | #### Returns 11 | The value undefined. 12 | 13 | #### Example 14 | `dialog.alert ("It's sunny outside.")` 15 | 16 | - *undefined* 17 | 18 | ## dialog.ask 19 | #### Syntax 20 | dialog.ask (prompt, default, placeholder) 21 | 22 | #### Params 23 | All parameters are strings. 24 | 25 | prompt is displayed over the text box, it's the question the user is meant to answer. 26 | 27 | default is the initial string in the text box. 28 | 29 | placeholder is a string that appears in the text box when it's empty. 30 | 31 | #### What it does 32 | A dialog with a text box and two buttons appears. The buttons are labeled Cancel and OK. 33 | 34 | The user can enter text to replace the default text, and then press Cancel or OK. 35 | 36 | If the user clicks Cancel, dialog.ask returns the value undefined. If the user clicks OK, it returns the string that's in the text box, as modified by the user. 37 | 38 | #### Returns 39 | The string the user entered if they pressed OK, or the value undefined if Cancel. 40 | 41 | #### Example 42 | `dialog.ask ("Favorite color?", "blue", "A color like blue or red goes here.")` 43 | 44 | - *orange* 45 | 46 | ## dialog.confirm 47 | #### Syntax 48 | dialog.confirm (string) 49 | 50 | #### Params 51 | The string is displayed in a dialog with two buttons, Cancel and OK. 52 | 53 | #### Returns 54 | A boolean, true if the user clicked OK, false if Cancel. 55 | 56 | #### Example 57 | `dialog.confirm ("Really erase all files on your computer?")` 58 | 59 | - *true* 60 | 61 | ## dialog.about 62 | #### Syntax 63 | dialog.about (string1, string2) 64 | 65 | #### Params 66 | The first string is the text of an OPML file. The second string is the title of the dialog, which is optional. 67 | 68 | #### What it does 69 | Displays the outline in a dialog, with the title at the top. 70 | 71 | #### Returns 72 | undefined. 73 | 74 | #### Example 75 | `dialog.about (http.readUrl ("http://scripting.com/states.opml"), "States outline")` 76 | 77 | - *undefined* 78 | 79 | -------------------------------------------------------------------------------- /webapp/styles.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font-family: "Ubuntu"; 4 | font-size: 16px; 5 | background-color: whitesmoke; 6 | } 7 | .divPageBody { 8 | margin-top: 80px; 9 | width: 700px; 10 | margin-left: auto; 11 | margin-right: auto; 12 | } 13 | .divVersionNumber { 14 | font-size: 12px; 15 | position: fixed; 16 | top: 0; 17 | right: 0; 18 | color: gray; 19 | padding-top: 17px; 20 | padding-right: 17px; 21 | } 22 | 23 | .divIndexPanel { 24 | display: table-cell; 25 | width: 150px; 26 | margin-right: 5px; 27 | border: 1px solid silver; 28 | padding: 3px; 29 | } 30 | .divSpacer { 31 | display: table-cell; 32 | width: 10px; 33 | } 34 | .divDocserverPanel { 35 | display: table-cell; 36 | width: 700px; 37 | vertical-align: top; 38 | margin-left: auto; 39 | margin-right: auto; 40 | border: 1px solid silver; 41 | padding: 7px; 42 | } 43 | .divDocserverPage { 44 | } 45 | 46 | 47 | .ulVerbList { 48 | margin: 0; 49 | } 50 | .ulVerbList li { 51 | list-style-type: none; 52 | font-size: 14px; 53 | cursor: pointer; 54 | padding: 2px; 55 | } 56 | .ulVerbList .liCursor { 57 | background-color: #086DD6; 58 | color: white; 59 | } 60 | 61 | .divDocserverNavLinks { 62 | font-size: 14px; 63 | margin-bottom: 30px; 64 | } 65 | .divNavleft { 66 | cursor: pointer; 67 | } 68 | .divNavright { 69 | float: right; 70 | cursor: pointer; 71 | } 72 | .navicon { 73 | color: green; 74 | width: 14px; 75 | heigth: 14px; 76 | } 77 | .dsTitle { 78 | font-size: 36px; 79 | font-weight: bold; 80 | margin-bottom: 10px; 81 | letter-spacing: -1px; 82 | } 83 | .dsOrangeLine, .dsBlackLine { 84 | width: 100%; 85 | height: 3px; 86 | opacity: 0.9; 87 | background-color: orange; 88 | margin-top: 15px; 89 | margin-bottom: 10px; 90 | } 91 | .dsOrangeLine { 92 | margin-top: 25px; 93 | margin-bottom: 25px; 94 | } 95 | .dsBlackLine { 96 | background-color: gray; 97 | height: 1px; 98 | margin-top: 1px; 99 | } 100 | .dsSection { 101 | display: table-row; 102 | } 103 | .dsSectionTitle { 104 | display: table-cell; 105 | text-align: right; 106 | font-weight: bold; 107 | margin-top: 10px; 108 | padding-right: 1em; 109 | white-space: nowrap; 110 | } 111 | .dsSectionText { 112 | display: table-cell; 113 | } 114 | .dsSectionText ul { 115 | margin-left: 15px; 116 | } 117 | .dsSectionPgf li { 118 | list-style-type: none; 119 | margin-top: 5px; 120 | } 121 | .isComment { 122 | font-family: monospace; 123 | font-size: 0.9em; 124 | line-height: 120%; 125 | } 126 | 127 | .divOutlineJson { 128 | display: none; 129 | } 130 | .divConsts { 131 | display: none; 132 | } 133 | .divPrefs { 134 | display: none; 135 | } 136 | 137 | .divIndexPanel { 138 | display: none; 139 | } 140 | .divMenubar .nav li { 141 | font-size: 14px; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /docs/pages/rss.md: -------------------------------------------------------------------------------- 1 | 2 | # rss verbs 3 | ## rss.readFeed 4 | #### Syntax 5 | rss.readFeed (url) 6 | 7 | #### Params 8 | The url is the address of an RSS feed. 9 | 10 | #### Returns 11 | A JavaScript object with the contents of the feed. 12 | 13 | #### Note 14 | It can handle most versions of RSS and Atom. 15 | 16 | #### Example 17 | `rss.readFeed ("http://scripting.com/rss.xml")` 18 | 19 |
{
20 |     "title": "Scripting News",
21 |     "description": "It's even worse than it appears.",
22 |     "pubDate": "2021-11-17T18:40:46.000Z",
23 |     "link": "http://oldschool.scripting.com/davewiner/",
24 |     "language": "en-us",
25 |     "copyright": "copyright 1994-2021 Dave Winer.",
26 |     "generator": "oldSchool v0.7.12",
27 |     "cloud": {
28 |         "domain": "rpc.rsscloud.io",
29 |         "port": "5337",
30 |         "path": "/pleaseNotify",
31 |         "registerprocedure": "",
32 |         "protocol": "http-post",
33 |         "type": "rsscloud"
34 |         },
35 |     "items": [
36 |         {
37 |             "description": "New verb coming soon in Drummer, rss.readFeed. It takes the URL of an RSS feed, and returns a JavaScript object containg the information in the feed in an easy-to-use format  (for programmers of course).",
38 |             "pubDate": "2021-11-19T18:30:39.000Z",
39 |             "link": "http://scripting.com/2021/11/19.html#a183039",
40 |             "guid": "http://scripting.com/2021/11/19.html#a183039"
41 |             },
42 |         {
43 |             "description": "I missed the renewal notices for the Radio3.io domain, so it's out now, but I expect it'll be back shortly. Sorry! :-(",
44 |             "pubDate": "2021-11-19T17:38:44.000Z",
45 |             "link": "http://scripting.com/2021/11/19.html#a173844",
46 |             "guid": "http://scripting.com/2021/11/19.html#a173844"
47 |             },
48 |         {
49 |             "description": "A discussion about how Markdown should be processed for Drummer blogs. Basically, what role if any should indentation play, and how many newlines to generate for each line in the outline. My current position -- indentation should play no role in the Markdown we generate from the outline, it should be ignored. And we should generate one newline for every line in the outline. Note this is not how Drummer works now.",
50 |             "pubDate": "2021-11-19T15:16:46.000Z",
51 |             "link": "http://scripting.com/2021/11/19.html#a151646",
52 |             "guid": "http://scripting.com/2021/11/19.html#a151646"
53 |             },
54 |         {
55 |             "description": "I did a refresh on the ArtShow collection yesterday, a few hundred more classic paintings. Free to download, or use via web.",
56 |             "pubDate": "2021-11-18T12:14:39.000Z",
57 |             "link": "http://scripting.com/2021/11/18.html#a121439",
58 |             "guid": "http://scripting.com/2021/11/18.html#a121439"
59 |             },
60 |     }
61 | 
62 | -------------------------------------------------------------------------------- /docs/pages/drummer.md: -------------------------------------------------------------------------------- 1 | 2 | # drummer verbs 3 | ## drummer.productname 4 | #### Syntax 5 | drummer.productname () 6 | 7 | #### Params 8 | None 9 | 10 | #### Returns 11 | The name of the Drummer app. 12 | 13 | #### Notes 14 | At first it might seem silly to have a verb that tells your script the name of the Drummer app, but these things do change sometimes. 15 | 16 | For example, there was a scripting language in the Fargo app, and it's possible someone might run one of its scripts here. 17 | 18 | fargo.version is implemented here, so you can find out that this isn't Fargo anymore, if your script cares. 19 | 20 | When you've been doing this for a long time, the value of these kinds of hooks become apparent. 21 | 22 | #### Examples 23 | `drummer.productname ()` 24 | 25 | - *"drummer"* 26 | 27 | ## drummer.productnameForDisplay 28 | #### Syntax 29 | drummer.productnameForDisplay () 30 | 31 | #### Params 32 | None 33 | 34 | #### Returns 35 | The name of the Drummer app in a form suitable for displaying in a dialog, or other kind of message to the user. 36 | 37 | #### Examples 38 | `drummer.productnameForDisplay ()` 39 | 40 | - *"Drummer"* 41 | 42 | ## drummer.runScript 43 | #### Syntax 44 | drummer.runScript (string) 45 | 46 | #### Params 47 | The string is a bit of JavaScript code. 48 | 49 | #### Returns 50 | undefined. 51 | 52 | #### Notes 53 | The script text runs but I was hoping the value would be returned, but it's not. 54 | 55 | In the second example below, nothing happens. 56 | 57 | #### Examples 58 | `drummer.runScript ("dialog.alert (\"Hello World\")")` 59 | 60 | - *undefined* 61 | 62 | `drummer.runScript ("100 * 12")` 63 | 64 | - *undefined* 65 | 66 | ## drummer.subscribeToOutline 67 | #### Syntax 68 | drummer.subscribeToOutline (string) 69 | 70 | #### Params 71 | The string is the URL of an OPML file. 72 | 73 | #### What it does 74 | The outline opens in a new tab, or if it's already open, Drummer brings the tab to the front. 75 | 76 | #### Returns 77 | true. 78 | 79 | #### Notes 80 | If the outline has a <urlUpdateSocket> head element, Drummer will request updates from the server, and will automatically update the outline when the outline changes. 81 | 82 | See the instantOutlines project for examples and code for this protocol. 83 | 84 | #### Examples 85 | `drummer.subscribeToOutline ("http://scripting.com/states.opml")` 86 | 87 | - *true* 88 | 89 | ## drummer.version 90 | #### Syntax 91 | drummer.version () 92 | 93 | #### Params 94 | None 95 | 96 | #### Returns 97 | The current version of the Drummer software. 98 | 99 | #### Examples 100 | `drummer.version ()` 101 | 102 | - *2.0.6* 103 | 104 | ## drummer.useStylesheet 105 | #### Syntax 106 | drummer.useStylesheet (string) 107 | 108 | #### Params 109 | The string is the URL of an CSS style sheet file. 110 | 111 | #### What it does 112 | Applies the style sheet to Drummer. 113 | 114 | #### Returns 115 | true. 116 | 117 | #### Notes 118 | We're using this Stack Overflow piece as guidance. 119 | 120 | #### Example 121 | `drummer.useStylesheet ("http://scripting.com/misc/darkmodestyles.css")` 122 | 123 | - *true* 124 | 125 | -------------------------------------------------------------------------------- /docs/pages/oldSchool.md: -------------------------------------------------------------------------------- 1 | 2 | # oldSchool verbs 3 | ## oldSchool.buildBlog 4 | #### Syntax 5 | oldSchool.buildBlog (boolean) 6 | 7 | #### Params 8 | The boolean, which is options, says whether or not you want all the data returned by Old School to be returned by this verb. 9 | 10 | #### What it does 11 | Calls drummercms.scripting.com telling it to build the user's Old School blog. 12 | 13 | #### Returns 14 | The web address of the user's blog if the boolean is false, otherwise all the data Old School returns in the form of a JavaScript object. 15 | 16 | #### Example 17 | `oldSchool.buildBlog ()` 18 | 19 | - *http://oldschool.scripting.com/cluelessnewbie/* 20 | 21 | `oldSchool.buildBlog (true)` 22 | 23 |
{
24 |     "baseUrl": "http://clueless.lucky.wtf/",
25 |     "ctSecs": 1.199,
26 |     "oldSchoolVersion": "0.7.9",
27 |     "eventLog": {
28 |         "pagesPublished": [
29 |             "2021/10/30/174131.html",
30 |             "2021/10/30/152252.html",
31 |             "2021/10/30.html",
32 |             "index.html",
33 |             "homepage.html",
34 |             "rss.json",
35 |             "fb/rss.xml",
36 |             "index.json"
37 |             ],
38 |         "pingsSent": [
39 |             {
40 |                 "urlServer": "http://rpc.rsscloud.io:5337/ping",
41 |                 "urlFeed": "http://clueless.lucky.wtf/rss.json"
42 |                 },
43 |             {
44 |                 "urlServer": "http://rpc.rsscloud.io:5337/ping",
45 |                 "urlFeed": "http://clueless.lucky.wtf/fb/rss.xml"
46 |                 }
47 |             ]
48 |         },
49 |     "headLevelAtts": {
50 |         "dateCreated": "Mon, 09 Aug 2021 16:53:40 GMT",
51 |         "flPublic": "true",
52 |         "urlPublic": "http://oldschool.scripting.com/cluelessnewbie/",
53 |         "description": "Searching for clues, so far no luck.",
54 |         "urlHeaderImage": "http://scripting.com/images/2020/10/05/sky.png",
55 |         "copyright": "copyright 2021 Dave Winer",
56 |         "titlex": "I don't have a clue",
57 |         "title": "No clues",
58 |         "urlGlossary": "http://scripting.com/publicfolder/misc/glossary.opml",
59 |         "urlLinkblogJson": "http://radio3.io/users/davewiner/linkblog.json",
60 |         "urlAboutOpml": "http://drummer.scripting.com/cluelessnewbie/about.opml",
61 |         "urlBlogWebsite": "http://clueless.lucky.wtf/",
62 |         "timeZoneOffset": "-5",
63 |         "urlTemplate": "http://scripting.com/code/drummercms/templates/minimal/index.html",
64 |         "ownerTwitterScreenName": "cluelessnewbie",
65 |         "ownerName": "Clueless Newbie",
66 |         "ownerId": "http://twitter.com/cluelessnewbie",
67 |         "urlUpdateSocket": "ws://drummer.scripting.com:1232/",
68 |         "dateModified": "Sun, 31 Oct 2021 15:07:36 GMT",
69 |         "expansionState": "1,2,8,13,14",
70 |         "lastCursor": "12",
71 |         "generator": "opmlPackage v0.4.9"
72 |         }
73 |     }
74 | 
75 | ## oldSchool.getCursorLink 76 | #### Syntax 77 | oldSchool.getCursorLink () 78 | 79 | #### Params 80 | None. 81 | 82 | #### Returns 83 | The URL of the rendering of the bar cursor headline, if it's part of a blog. 84 | 85 | The file must have a head-level urlBlogWebsite attribute, if not oldSchool.getCursorLink returns undefined. 86 | 87 | If the cursor points into a titled post, the URL points to the specific line in the post the cursor points to. 88 | 89 | #### Note 90 | This functionality is wired into the Eye icon. 91 | 92 | #### Example 93 | `oldSchool.getCursorLink ()` 94 | 95 | - *http://clueless.lucky.wtf/2021/11/14.html#a232957* 96 | 97 | -------------------------------------------------------------------------------- /docs/pages/tab.md: -------------------------------------------------------------------------------- 1 | 2 | # tab verbs 3 | ## tab.getActiveTabStatus 4 | #### Syntax 5 | tab.getActiveTabStatus () 6 | 7 | #### Params 8 | None. 9 | 10 | #### Returns 11 | A JavaScript object containing information about the file in the active tab. 12 | 13 | #### Note 14 | This is the actual internal information Drummer uses to keep track of the tab. 15 | 16 | #### Values 17 | flActive -- will always be true. 18 | 19 | name -- the title of the file. 20 | 21 | fname -- the file name, in Electric Drummer, the full path to the file. 22 | 23 | flInstantOutline -- true if it's an instant outline. 24 | 25 | flReadOnly -- true for instant outlines, false for outlines you create. 26 | 27 | flLocked -- applies to instant outlines. True if the outline is locked, which means updates won't be displayed until the user unlocks the file. 28 | 29 | flPrivate -- true if the file is private. 30 | 31 | serialnum -- a unique number assigned to this tab by Drummer. 32 | 33 | #### Examples 34 | `tab.getActiveTabStatus ()` 35 | 36 |
{
 37 |     "flActive": true,
 38 |     "name": "Scratchpad",
 39 |     "fname": "scratchpad.opml",
 40 |     "flReadOnly": false,
 41 |     "flInstantOutline": false,
 42 |     "serialnum": 3,
 43 |     "flLocked": false,
 44 |     "flPrivate": true
 45 |     }
 46 | 
47 | `tab.getActiveTabStatus ().fname` 48 | 49 | - */Users/davewiner/docserver source/verbDocs.opml* 50 | 51 | `file.getFileInfo (tab.getActiveTabStatus ().fname)` 52 | 53 |
{
 54 |     "size": 81644,
 55 |     "whenAccessed": "2022-01-06T21:00:09.000Z",
 56 |     "whenCreated": "2021-07-30T13:35:09.000Z",
 57 |     "whenModified": "2022-01-06T21:19:05.000Z",
 58 |     "flPrivate": true
 59 |     }
 60 | 
61 | ## tab.getPublicUrl 62 | #### Syntax 63 | tab.getPublicUrl () returns string 64 | 65 | #### What it does 66 | If the outline in the current tab in the outliner is public, returns the HTTP address of the file. 67 | 68 | If the outline is private, returns undefined. 69 | 70 | #### Returns 71 | A web address or undefined. 72 | 73 | #### Example 74 | `dialog.alert (tab.getPublicUrl ())` 75 | 76 | - *undefined* 77 | 78 | ## tab.openFile 79 | #### Syntax 80 | tab.openFile (string, string) 81 | 82 | #### Params 83 | The first string is the name of an existing outline file. 84 | 85 | The second string is optional, it's the title you want to appear in the tab. If not specified, the outline's title is displayed in the tab. 86 | 87 | #### What it does 88 | If the file is already open in a tab, that tab comes to the front. If not, and the file exists, it opens in a new tab. 89 | 90 | #### Returns 91 | true 92 | 93 | #### Common error 94 | The file does not exist. 95 | 96 | #### Examples 97 | `tab.openFile ("hello3.opml") ` 98 | 99 | - *true* 100 | 101 | `tab.openFile ("hello3.opml", "My Favorite File") ` 102 | 103 | - *true* 104 | 105 | ## tab.openInstantOutline 106 | #### Syntax 107 | tab.openInstantOutline (string, string) 108 | 109 | #### Params 110 | The first string is the URL of an instant outline descriptor file. 111 | 112 | The second string is optional, it's the title you want to appear in the tab. If not specified, the outline's title is displayed in the tab. 113 | 114 | #### What it does 115 | If the outline is already open in a tab, that tab comes to the front. If not, and the file exists, it opens in a new tab. 116 | 117 | #### Returns 118 | true. 119 | 120 | #### Bug 121 | It has no way to report an error, if it couldn't open the outline, it still returns true. 122 | 123 | #### Examples 124 | `tab.openInstantOutline ("http://instantoutliner.com/o0", "The states outline") ` 125 | 126 | - *true* 127 | 128 | -------------------------------------------------------------------------------- /docs/pages/http.md: -------------------------------------------------------------------------------- 1 | 2 | # http verbs 3 | ## http.client 4 | #### Syntax 5 | http.client (options, boolean) 6 | 7 | #### Parameters 8 | options is a JavaScript structure that defines the request. 9 | 10 | boolean indicates whether it uses a proxy server (true) or the request is made from the browser (false). 11 | 12 | #### Returns 13 | What the HTTP request returns. 14 | 15 | #### Breakage 16 | There will be breakage. If you want to use this now, be prepared to adjust your code later, and participate in the thread on the RFC site. As long as this alert is here, assume your apps that use this verb will break. 17 | 18 | #### Notes 19 | This is meant to be a complete HTTP client that's accessible to Drummer programmers. 20 | 21 | In its first release in November 2021, it is far from complete. But it gives you a lot more power than the simpler http.readUrl. Most important probably is that http.client can do requests other than GET. 22 | 23 | The options struct is what you would pass to a jQuery AJAX call. Here's a list of values it looks for: 24 | 25 | - *type -- the HTTP method, such as GET, POST, HEAD. * 26 | 27 | - *url -- the address the request is directed to* 28 | 29 | - *data -- the data that is passed in the body of the request. * 30 | 31 | - *params -- a JavaScript object containing the search params for the request. * 32 | 33 | There's a new endpoint in daveappserver that acts as the proxy server for this verb. It is deployed at drummer.scripting.com. 34 | 35 | It's named after the Frontier verb tcp.httpClient, which had a very long param list. In this version I opted for a struct instead. The intention is to do all that the Frontier verb does in this verb, in Drummer. 36 | 37 | #### Examples 38 | `http.client ({url: "http://drummer.scripting.com/now"}, true)` 39 | 40 | - *Fri Nov 05 2021 13:05:15 GMT-0400 (Eastern Daylight Time)* 41 | 42 | ## http.readUrl 43 | #### Syntax 44 | http.readUrl (string, boolean) 45 | 46 | #### Parameters 47 | The string is the http address of the page you want to read. 48 | 49 | The boolean indicates whether you want to go through a proxy server for the request. It's optional, and it's default value is true. 50 | 51 | #### Returns 52 | It makes an HTTP request and returns to the caller what the request returns. 53 | 54 | #### Notes 55 | If you want to access a resource on the local machine, or one that is inaccessible to drummer.scripting.com for some reason, you must not use the proxy server. 56 | 57 | If you can make the request without using the proxy server it will be faster, and conserves resources. 58 | 59 | #### Examples 60 | `http.readUrl ("http://scripting.com/rss.xml", false).length` 61 | 62 | - *73700* 63 | 64 | `http.readUrl ("http://scripting.com/rss.xml", false).length` 65 | 66 | - *73700* 67 | 68 | `http.readUrl ("http://localhost:1410/now", false)` 69 | 70 | - *Mon Aug 09 2021 16:35:28 GMT-0400 (Eastern Daylight Time)* 71 | 72 | ## http.derefUrl 73 | #### Syntax 74 | http.derefUrl (string) 75 | 76 | #### Parameters 77 | The string is a shortened http address. In other words and address that points to another address. 78 | 79 | #### Returns 80 | If the address is not a shortened url, it returns the address itself. If it is, it returns the address that it points to. 81 | 82 | #### Notes 83 | 9/17/2021 by DW -- it does not work in the case that the address is not a shortened url. Not sure why, no time to investigate at this time. 84 | 85 | #### Examples 86 | `http.derefUrl ("https://tinyurl.com/yvfkvaps")` 87 | 88 | - *http://scripting.com/* 89 | 90 | `http.derefUrl ("https://scripting.com/")` 91 | 92 | - *http://scripting.com/* 93 | 94 | -------------------------------------------------------------------------------- /webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | DocServer 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 |
38 | 72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | 			[%outlineJson%]
84 | 			
85 |
86 | 			
87 |
88 | 			
89 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /docs/pages/date.md: -------------------------------------------------------------------------------- 1 | 2 | # date verbs 3 | ## date.convertToTimeZone 4 | #### Syntax 5 | date.convertToTimeZone (date, string) 6 | 7 | #### Params 8 | The date param is the date you want to convert to a different time zone. 9 | 10 | The string says how far from GMT and in what direction the other time zone is. For example -5 would be the string for the east coast of the United States, meaning five hours earlier than GMT. "0" is GMT. This param is optional, if not specified it is "0". 11 | 12 | The string param does not have to represent a whole hour. For example Central Indian Time is "+5:30". 13 | 14 | #### Returns 15 | The date, expressed in the indicated time zone. 16 | 17 | If x is a date returned by this routine, you can use the JavaScript date functions to get components of a time, getHours, getMinutes, etc and they will return the correct values for the indicated time zone. 18 | 19 | This is a core routine for building blogs that might be published by software running in a time zone different from the author of the blog. 20 | 21 | #### Examples 22 | `date.convertToTimeZone (clock.now (), "+5:30").toLocaleString ()` 23 | 24 | - *11/15/2021, 8:45:29 PM* 25 | 26 | ## date.dayGreaterThanOrEqual 27 | #### Syntax 28 | date.dayGreaterThanOrEqual (d1, d2) 29 | 30 | #### Params 31 | Both parameters are JavaScript date objects. 32 | 33 | #### Returns 34 | true if the first date is on the same day as the second, or if the first date is later than the second. 35 | 36 | #### Notes 37 | This verb is useful in determining which version of software you're running, if you have the publication date of a new version. Also useful to see if a timer has expired. 38 | 39 | #### Example 40 | `date.dayGreaterThanOrEqual (clock.now (), "November 22, 2018")` 41 | 42 | - *true* 43 | 44 | ## date.netStandardString 45 | #### Syntax 46 | date.netStandardString (date) 47 | 48 | #### Params 49 | date is a JavaScript date object. 50 | 51 | #### Returns 52 | A RFC 822 version of the date. 53 | 54 | #### Notes 55 | This is the format that's required for RSS feeds, OPML files and mail protocols. 56 | 57 | It's a human and machine readable way of expressing of dates. 58 | 59 | #### Examples 60 | `date.netStandardString (clock.now ())` 61 | 62 | - *Sun, 14 Mar 2021 16:28:56 GMT* 63 | 64 | `date.netStandardString ("12/5/97; 9:03:15 PM")` 65 | 66 | - *Sat, 06 Dec 1997 04:03:15 GMT* 67 | 68 | ## date.sameDay 69 | #### Syntax 70 | date.sameDay (d1, d2) 71 | 72 | #### Params 73 | Both parameters are JavaScript date objects. 74 | 75 | #### Returns 76 | true if the dates are on the same day, false otherwise. 77 | 78 | #### Examples 79 | `date.sameDay ("March 12, 2021", "February 12, 2021")` 80 | 81 | - *false* 82 | 83 | `date.sameDay ("March 12, 2021", "March 12, 2021")` 84 | 85 | - *true* 86 | 87 | ## date.sameMonth 88 | #### Syntax 89 | date.sameMonth (d1, d2) 90 | 91 | #### Params 92 | Both parameters are JavaScript date objects. 93 | 94 | #### Returns 95 | true if the dates are in the same month, false otherwise. 96 | 97 | #### Examples 98 | `date.sameMonth ("March 12, 2021", "February 12, 2021")` 99 | 100 | - *false* 101 | 102 | `date.sameMonth ("March 12, 2021", "March 30, 2021")` 103 | 104 | - *true* 105 | 106 | ## date.secondsSince 107 | #### Syntax 108 | date.secondsSince (date) 109 | 110 | #### Params 111 | date is a JavaScript date object. 112 | 113 | #### Returns 114 | The number of seconds since the date. 115 | 116 | #### Notes 117 | Useful when you want to know how long something took. 118 | 119 | #### Example 120 | `date.secondsSince ("March 14, 2020")` 121 | 122 | - *31580389.57* 123 | 124 | ## date.tomorrow 125 | #### Syntax 126 | date.tomorrow (date) 127 | 128 | #### Params 129 | date is a JavaScript date object. 130 | 131 | #### Returns 132 | The result of adding 24 hours from the date. 133 | 134 | #### Example 135 | `date.tomorrow (clock.now ())` 136 | 137 | - *Mon Mar 15 2021 12:21:22 GMT-0400 (Eastern Daylight Time)* 138 | 139 | ## date.yesterday 140 | #### Syntax 141 | date.yesterday (date) 142 | 143 | #### Params 144 | date is a JavaScript date object. 145 | 146 | #### Returns 147 | The result of subtracting 24 hours from the date. 148 | 149 | #### Example 150 | `date.yesterday (clock.now ())` 151 | 152 | - *Sat Mar 13 2021 11:21:02 GMT-0500 (Eastern Standard Time)* 153 | 154 | -------------------------------------------------------------------------------- /docs/pages/daytona.md: -------------------------------------------------------------------------------- 1 | 2 | # daytona verbs 3 | ## daytona.ping 4 | #### Syntax 5 | daytona.ping (urlOutline, collection) 6 | 7 | #### Params 8 | The first param is the URL of a public outline containing the content you want to be included in your Daytona index. 9 | 10 | The second param is optional and defaults to "drummeruser." For most users that's the only value that will work. 11 | 12 | #### What it does 13 | Queues an indexing of the outline. It will usually take a minute or more for Daytona to index the outline. 14 | 15 | #### Returns 16 | A message saying it worked, if it did. 17 | 18 | #### Note 19 | Simply updating the outline is enough to get it to be reindexed, so in most cases you will not have to do the ping from a script. 20 | 21 | #### Example 22 | `daytona.ping ("http://drummer.scripting.com/cluelessnewbie/blog.opml")` 23 | 24 | - *all is good* 25 | 26 | ## daytona.query 27 | #### Syntax 28 | daytona.query (query, collection) 29 | 30 | #### Params 31 | The first param is a string that contains the string you want to search for. 32 | 33 | The second param is the collection you want to search in. It can be scriptingnews, drummerdocs or drummeruser. It's optional, if not present the default value is drummeruser. 34 | 35 | #### Returns 36 | The result of the query in a JavaScript object. 37 | 38 | #### Example 39 | `daytona.query ("BBC")` 40 | 41 |
[
 42 |     {
 43 |         "urloutline": "http://drummer.scripting.com/cluelessnewbie/blog.opml",
 44 |         "whencreated": "2021-12-05T17:11:16.000Z",
 45 |         "screenname": "cluelessnewbie",
 46 |         "title": "I'm doing another test!",
 47 |         "collection": "drummeruser",
 48 |         "jstruct": {
 49 |             "text": "I'm doing another test!",
 50 |             "created": "Sun, 05 Dec 2021 17:11:16 GMT",
 51 |             "type": "outline",
 52 |             "subs": [
 53 |                 {
 54 |                     "text": "Like a rolling stone",
 55 |                     "created": "Sun, 05 Dec 2021 22:16:43 GMT"
 56 |                     },
 57 |                 {
 58 |                     "text": "Like the FBI",
 59 |                     "created": "Sun, 05 Dec 2021 22:17:33 GMT"
 60 |                     },
 61 |                 {
 62 |                     "text": "And the CIA",
 63 |                     "created": "Sun, 05 Dec 2021 22:17:36 GMT"
 64 |                     },
 65 |                 {
 66 |                     "text": "BBC",
 67 |                     "created": "Sun, 05 Dec 2021 22:17:39 GMT"
 68 |                     },
 69 |                 {
 70 |                     "text": "BB King",
 71 |                     "created": "Sun, 05 Dec 2021 22:17:40 GMT"
 72 |                     },
 73 |                 {
 74 |                     "text": "And Doris Day",
 75 |                     "created": "Sun, 05 Dec 2021 22:17:44 GMT"
 76 |                     },
 77 |                 {
 78 |                     "text": "Buzz be",
 79 |                     "created": "Sun, 05 Dec 2021 22:17:47 GMT"
 80 |                     },
 81 |                 {
 82 |                     "text": "Buzz be",
 83 |                     "created": "Sun, 05 Dec 2021 22:17:51 GMT"
 84 |                     },
 85 |                 {
 86 |                     "text": "That was can you digit by xxx",
 87 |                     "created": "Sun, 05 Dec 2021 22:17:53 GMT"
 88 |                     },
 89 |                 {
 90 |                     "text": "Now we'd like to sing all the angels come",
 91 |                     "created": "Sun, 05 Dec 2021 22:18:01 GMT"
 92 |                     }
 93 |                 ]
 94 |             }
 95 |         }
 96 |     ]
 97 | 
98 | ## daytona.resetMyIndex 99 | #### Syntax 100 | daytona.resetMyIndex (collection) 101 | 102 | #### Param 103 | The param is the collection you want to search in. It can be scriptingnews, drummerdocs or drummeruser. It's optional, if not present the default value is drummeruser. For most users, the only value that will work is drummeruser. 104 | 105 | #### Returns 106 | true 107 | 108 | #### What it does 109 | Deletes all index entries for the indicated collection. You're basically saying you want to start over with the index. Then you can either make changes to the outlines you want to include in the index to get them re-indexed, or use the daytona.ping verb. 110 | 111 | #### Note 112 | daytona.removeOutlineRefs is more selective, it only removes references to one outline, not all of them. 113 | 114 | #### Example 115 | `daytona.resetMyIndex ()` 116 | 117 | - *true* 118 | 119 | ## daytona.removeOutlineRefs 120 | #### Syntax 121 | daytona.removeOutlineRefs (urlOutline, collection) 122 | 123 | #### Params 124 | The first param is the address of the public outline that you want removed from your Daytona index. 125 | 126 | The second param is the collection you want it removed from. It can be scriptingnews, drummerdocs or drummeruser. It's optional, if not present the default value is drummeruser. 127 | 128 | #### What it does 129 | Deletes all index entries for the indicated outline, so you can start over with the outline. We will do this with our blog.opml files when we archive the outline, removing all index references for the blog.opml file. If you don't, there will be double-references for posts that were archived, and even worse the ones that come from blog.opml won't be there if you click through the Eye icon to see the context. 130 | 131 | #### Returns 132 | true 133 | 134 | #### Example 135 | `daytona.removeOutlineRefs ("http://drummer.scripting.com/cluelessnewbie/blog.opml")` 136 | 137 | - *true* 138 | 139 | -------------------------------------------------------------------------------- /markdownapp/docservertomarkdown.js: -------------------------------------------------------------------------------- 1 | const myVersion = "0.4.2", myProductName = "docservertomarkdown"; 2 | 3 | var urlDocsOpml = "http://drummer.scripting.com/davewiner/verbDocs.opml"; 4 | 5 | const fs = require ("fs"); 6 | const utils = require ("daveutils"); 7 | const request = require ("request"); 8 | const opml = require ("opml"); 9 | const davegithub = require ("davegithub"); 10 | 11 | var config = { 12 | flUploadToGithub: false, 13 | flGenerateLocalFiles: true, 14 | 15 | localFolder: "", //set in config.json 16 | 17 | username: "scripting", 18 | repo: "docServer", 19 | repoPath: "docs/", 20 | 21 | githubPassword: "", 22 | 23 | baseRepoUrl: "https://github.com/scripting/docServer/blob/main/docs/", 24 | 25 | "committer": { 26 | "name": "Dave Winer", 27 | "email": "dave@scripting.com" 28 | }, 29 | "message": ".", 30 | 31 | "userAgent": "docservertomarkdown" 32 | }; 33 | 34 | function httpRequest (url, callback) { 35 | request (url, function (err, response, data) { 36 | if (err) { 37 | callback (err); 38 | } 39 | else { 40 | if (response.statusCode != 200) { 41 | const message = "The request returned a status code of " + response.statusCode + "."; 42 | callback ({message}); 43 | } 44 | else { 45 | callback (undefined, data) 46 | } 47 | } 48 | }); 49 | } 50 | function uploadToGithub (relpath, data, type, callback) { 51 | if (config.flUploadToGithub) { 52 | const options = { 53 | username: config.username, 54 | repo: config.repo, 55 | repoPath: config.repoPath + relpath, 56 | password: config.githubPassword, 57 | data: data, 58 | type: (type === undefined) ? "text/plain" : type, 59 | committer: config.committer, 60 | message: config.message, 61 | userAgent: config.userAgent 62 | }; 63 | davegithub.uploadFile (options, function (err, response, body) { 64 | console.log ("uploadToGithub: url == " + config.baseRepoUrl + relpath + ", status == " + response.statusCode); 65 | if (err) { 66 | console.log ("uploadToGithub: err.message == " + err.message); 67 | } 68 | if (callback !== undefined) { 69 | callback (); 70 | } 71 | }); 72 | } 73 | else { 74 | callback (); 75 | } 76 | } 77 | function writeLocalFile (relpath, data, callback) { 78 | if (config.flGenerateLocalFiles) { 79 | var f = config.localFolder + relpath; 80 | utils.sureFilePath (f, function () { 81 | fs.writeFile (f, data, function (err) { 82 | console.log ("writeToLocalFile: f == " + f); 83 | if (err) { 84 | console.log ("writeToLocalFile: err.message == " + err.message); 85 | } 86 | if (callback !== undefined) { 87 | callback (); 88 | } 89 | }); 90 | }); 91 | } 92 | else { 93 | if (callback !== undefined) { 94 | callback (); 95 | } 96 | } 97 | } 98 | function getCategoryFilename (theCategory) { 99 | return (utils.stringNthField (theCategory.text, " ", 1) + ".md"); 100 | } 101 | function uploadOneCategory (theCategory, callback) { 102 | var mdtext = "", indentlevel = 0; 103 | function add (s) { 104 | mdtext += s + "\n"; 105 | } 106 | function exampleResultToMarkdown (theExampleResult) { 107 | let mdtext = "", indentlevel = 0; 108 | function add (s) { 109 | mdtext += utils.filledString (" ", indentlevel) + s +"\n"; 110 | } 111 | function addNode (theNode, flSinglespace=false) { 112 | add (theNode.text); 113 | if (theNode.subs !== undefined) { 114 | for (var i = 0; i < theNode.subs.length; i++) { 115 | indentlevel++; 116 | addNode (theNode.subs [i]); 117 | indentlevel--; 118 | } 119 | } 120 | } 121 | addNode (theExampleResult); 122 | return (mdtext); 123 | } 124 | opml.expandInclude (theCategory, function (err, cat) { 125 | if (err) { 126 | console.log ("uploadOneCategory: err.message == " + err.message); 127 | } 128 | else { 129 | if (cat.subs !== undefined) { 130 | add (""); 131 | add ("# " + theCategory.text); 132 | for (var j = 0; j < cat.subs.length; j++) { 133 | var verb = cat.subs [j]; 134 | add ("## " + verb.text); 135 | for (var k = 0; k < verb.subs.length; k++) { 136 | var subtopic = verb.subs [k]; 137 | var flCodeSubs = (subtopic.text == "Example") || (subtopic.text == "Examples"); 138 | add ("#### " + subtopic.text); 139 | for (var m = 0; m < subtopic.subs.length; m++) { 140 | var line = subtopic.subs [m], linetext = line.text; 141 | if (flCodeSubs) { 142 | linetext = "`" + linetext + "`"; 143 | } 144 | add (linetext + "\n"); 145 | if (line.subs !== undefined) { 146 | for (var n = 0; n < line.subs.length; n++) { 147 | var exampleresult = line.subs [n]; 148 | if (exampleresult.subs === undefined) { //the usual case, a one-line value was returned 149 | add ("- *" + exampleresult.text + "*\n"); 150 | } 151 | else { 152 | add ("
" + exampleResultToMarkdown (exampleresult) + "
"); 153 | } 154 | } 155 | } 156 | } 157 | } 158 | } 159 | } 160 | 161 | var path = "pages/" + getCategoryFilename (theCategory); 162 | uploadToGithub (path, mdtext, undefined, function () { 163 | writeLocalFile (path, mdtext, function () { 164 | callback (); 165 | }); 166 | }); 167 | } 168 | }); 169 | } 170 | function uploadAllCategories (theOutline, callback) { 171 | var theCats = theOutline.opml.body.subs; 172 | function doNext (ix) { 173 | if (ix < theCats.length) { 174 | uploadOneCategory (theCats [ix], function () { 175 | doNext (ix + 1); 176 | }); 177 | } 178 | else { 179 | callback (); 180 | } 181 | } 182 | doNext (0); 183 | } 184 | function uploadIndex (theOutline, callback) { 185 | var mdtext = "", indentlevel = 0; 186 | function add (s) { 187 | mdtext += utils.filledString (" ", indentlevel) + s + "\n"; 188 | } 189 | var theCats = theOutline.opml.body.subs; 190 | add ("# Complete list of verbs"); 191 | 192 | function doNext (ix) { 193 | if (ix < theCats.length) { 194 | var fname = getCategoryFilename (theCats [ix]); 195 | opml.expandInclude (theCats [ix], function (err, cat) { 196 | if (err) { 197 | console.log ("uploadIndex: err.message == " + err.message); 198 | } 199 | else { 200 | if (cat.subs !== undefined) { 201 | for (var j = 0; j < cat.subs.length; j++) { 202 | var verb = cat.subs [j]; 203 | var url = "pages/" + fname + "#" + utils.stringLower (verb.name); 204 | add ("* [" + verb.text + "](" + url + ")"); 205 | } 206 | } 207 | } 208 | doNext (ix + 1); 209 | }); 210 | } 211 | else { 212 | var path = "readme.md"; 213 | uploadToGithub (path, mdtext, undefined, function () { 214 | writeLocalFile (path, mdtext, function () { 215 | callback (); 216 | }); 217 | }); 218 | } 219 | } 220 | doNext (0); 221 | 222 | } 223 | function readConfig (f, theConfig, callback) { 224 | fs.readFile (f, function (err, jsontext) { 225 | if (!err) { 226 | try { 227 | var jstruct = JSON.parse (jsontext); 228 | for (var x in jstruct) { 229 | theConfig [x] = jstruct [x]; 230 | } 231 | } 232 | catch (err) { 233 | console.log ("readConfig: err.message == " + err.message); 234 | } 235 | } 236 | callback (); 237 | }); 238 | } 239 | 240 | readConfig ("config.json", config, function () { 241 | console.log ("config == " + utils.jsonStringify (config)); 242 | httpRequest (urlDocsOpml, function (err, opmltext) { 243 | if (err) { 244 | console.log (err.message); 245 | } 246 | else { 247 | opml.parse (opmltext, function (err, theOutline) { 248 | if (err) { 249 | console.log (err.message); 250 | } 251 | else { 252 | uploadAllCategories (theOutline, function () { 253 | uploadIndex (theOutline, function () { 254 | console.log (""); //skip line 255 | }); 256 | }) 257 | } 258 | }); 259 | } 260 | }) 261 | }); 262 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # Complete list of verbs 2 | * [base64.encode](pages/base64.md#base64encode) 3 | * [base64.decode](pages/base64.md#base64decode) 4 | * [clock.now](pages/clock.md#clocknow) 5 | * [clock.waitSeconds](pages/clock.md#clockwaitseconds) 6 | * [date.convertToTimeZone](pages/date.md#dateconverttotimezone) 7 | * [date.dayGreaterThanOrEqual](pages/date.md#datedaygreaterthanorequal) 8 | * [date.netStandardString](pages/date.md#datenetstandardstring) 9 | * [date.sameDay](pages/date.md#datesameday) 10 | * [date.sameMonth](pages/date.md#datesamemonth) 11 | * [date.secondsSince](pages/date.md#datesecondssince) 12 | * [date.tomorrow](pages/date.md#datetomorrow) 13 | * [date.yesterday](pages/date.md#dateyesterday) 14 | * [daytona.ping](pages/daytona.md#) 15 | * [daytona.query](pages/daytona.md#) 16 | * [daytona.resetMyIndex](pages/daytona.md#) 17 | * [daytona.removeOutlineRefs](pages/daytona.md#) 18 | * [dialog.alert](pages/dialog.md#dialogalert) 19 | * [dialog.ask](pages/dialog.md#dialogask) 20 | * [dialog.confirm](pages/dialog.md#dialogconfirm) 21 | * [dialog.about](pages/dialog.md#dialogabout) 22 | * [dns.getDomainName](pages/dns.md#dnsgetdomainname) 23 | * [dns.getDottedId](pages/dns.md#dnsgetdottedid) 24 | * [drummer.productname](pages/drummer.md#drummerproductname) 25 | * [drummer.productnameForDisplay](pages/drummer.md#drummerproductnamefordisplay) 26 | * [drummer.runScript](pages/drummer.md#drummerrunscript) 27 | * [drummer.subscribeToOutline](pages/drummer.md#drummersubscribetooutline) 28 | * [drummer.version](pages/drummer.md#drummerversion) 29 | * [drummer.useStylesheet](pages/drummer.md#drummerusestylesheet) 30 | * [file.exists](pages/file.md#fileexists) 31 | * [file.writeWholeFile](pages/file.md#filewritewholefile) 32 | * [file.readWholeFile](pages/file.md#filereadwholefile) 33 | * [file.delete](pages/file.md#filedelete) 34 | * [file.getFileInfo](pages/file.md#filegetfileinfo) 35 | * [file.makeFilePublic](pages/file.md#filemakefilepublic) 36 | * [file.getFileHierarchy](pages/file.md#filegetfilehierarchy) 37 | * [github.connectViaOauth](pages/github.md#githubconnectviaoauth) 38 | * [github.disconnect](pages/github.md#githubdisconnect) 39 | * [github.download](pages/github.md#githubdownload) 40 | * [github.getAccessToken](pages/github.md#githubgetaccesstoken) 41 | * [github.getDirectory](pages/github.md#githubgetdirectory) 42 | * [github.getUserInfo](pages/github.md#githubgetuserinfo) 43 | * [github.upload](pages/github.md#githubupload) 44 | * [http.client](pages/http.md#httpclient) 45 | * [http.readUrl](pages/http.md#httpreadurl) 46 | * [http.derefUrl](pages/http.md#httpderefurl) 47 | * [oldSchool.buildBlog](pages/oldSchool.md#oldschoolbuildblog) 48 | * [oldSchool.getCursorLink](pages/oldSchool.md#oldschoolgetcursorlink) 49 | * [op.attributes.addGroup](pages/op.md#) 50 | * [op.attributes.deleteOne](pages/op.md#) 51 | * [op.attributes.exists](pages/op.md#) 52 | * [op.attributes.getAll](pages/op.md#) 53 | * [op.attributes.getOne](pages/op.md#) 54 | * [op.attributes.makeEmpty](pages/op.md#) 55 | * [op.attributes.setOne](pages/op.md#) 56 | * [op.bold](pages/op.md#) 57 | * [op.collapseEverything](pages/op.md#) 58 | * [op.collapse](pages/op.md#) 59 | * [op.countSubs](pages/op.md#) 60 | * [op.deleteSubs](pages/op.md#) 61 | * [op.demote](pages/op.md#) 62 | * [op.expandAllLevels](pages/op.md#) 63 | * [op.expand](pages/op.md#) 64 | * [op.expandTo](pages/op.md#) 65 | * [op.firstSummit](pages/op.md#) 66 | * [op.getCursorJstruct](pages/op.md#) 67 | * [op.getCursorOpml](pages/op.md#) 68 | * [op.getCursor](pages/op.md#) 69 | * [op.getLineText](pages/op.md#) 70 | * [op.getOutlineJstruct](pages/op.md#) 71 | * [op.getRenderMode](pages/op.md#) 72 | * [op.getSelectedText](pages/op.md#) 73 | * [op.go](pages/op.md#) 74 | * [op.hasSubs](pages/op.md#) 75 | * [op.insertInCalendar](pages/op.md#) 76 | * [op.insertOpml](pages/op.md#) 77 | * [op.insert](pages/op.md#) 78 | * [op.isComment](pages/op.md#) 79 | * [op.italic](pages/op.md#) 80 | * [op.link](pages/op.md#) 81 | * [op.makeComment](pages/op.md#) 82 | * [op.promote](pages/op.md#) 83 | * [op.reorg](pages/op.md#) 84 | * [op.replaceSelectedText](pages/op.md#) 85 | * [op.runSelection](pages/op.md#) 86 | * [op.setCursor](pages/op.md#) 87 | * [op.setLineText](pages/op.md#) 88 | * [op.setRenderMode](pages/op.md#) 89 | * [op.setTextMode](pages/op.md#) 90 | * [op.strikethrough](pages/op.md#) 91 | * [op.toggleComment](pages/op.md#) 92 | * [op.toggleRenderMode](pages/op.md#) 93 | * [op.visitAll](pages/op.md#) 94 | * [op.visitSubs](pages/op.md#) 95 | * [op.visitToSummit](pages/op.md#) 96 | * [opml.parse](pages/opml.md#opmlparse) 97 | * [opml.stringify](pages/opml.md#opmlstringify) 98 | * [opml.attributes.addGroup](pages/opml.md#opmlattributesaddgroup) 99 | * [opml.attributes.deleteOne](pages/opml.md#opmlattributesdeleteone) 100 | * [opml.attributes.exists](pages/opml.md#opmlattributesexists) 101 | * [opml.attributes.getAll](pages/opml.md#opmlattributesgetall) 102 | * [opml.attributes.getOne](pages/opml.md#opmlattributesgetone) 103 | * [opml.attributes.makeEmpty](pages/opml.md#opmlattributesmakeempty) 104 | * [opml.attributes.setAll](pages/opml.md#opmlattributessetall) 105 | * [opml.attributes.setOne](pages/opml.md#opmlattributessetone) 106 | * [opml.getCurrentObject](pages/opml.md#opmlgetcurrentobject) 107 | * [opml.getCurrentOpml](pages/opml.md#opmlgetcurrentopml) 108 | * [opml.getMarkdown](pages/opml.md#opmlgetmarkdown) 109 | * [opml.getHeaders](pages/opml.md#opmlgetheaders) 110 | * [opml.setHeaders](pages/opml.md#opmlsetheaders) 111 | * [rss.readFeed](pages/rss.md#rssreadfeed) 112 | * [speaker.beep](pages/speaker.md#speakerbeep) 113 | * [string.addCommas](pages/string.md#stringaddcommas) 114 | * [string.addPeriodAtEnd](pages/string.md#stringaddperiodatend) 115 | * [string.beginsWith](pages/string.md#stringbeginswith) 116 | * [string.bumpUrlString](pages/string.md#stringbumpurlstring) 117 | * [string.contains](pages/string.md#stringcontains) 118 | * [string.countFields](pages/string.md#stringcountfields) 119 | * [string.dayOfWeekToString](pages/string.md#stringdayofweektostring) 120 | * [string.decodeXml](pages/string.md#stringdecodexml) 121 | * [string.delete](pages/string.md#stringdelete) 122 | * [string.encodeHtml](pages/string.md#stringencodehtml) 123 | * [string.endsWith](pages/string.md#stringendswith) 124 | * [string.extensionToMimeType](pages/string.md#stringextensiontomimetype) 125 | * [string.filledString](pages/string.md#stringfilledstring) 126 | * [string.formatDate](pages/string.md#stringformatdate) 127 | * [string.getRandomPassword](pages/string.md#stringgetrandompassword) 128 | * [string.hashMD5](pages/string.md#stringhashmd5) 129 | * [string.innerCaseName](pages/string.md#stringinnercasename) 130 | * [string.insert](pages/string.md#stringinsert) 131 | * [string.isAlpha](pages/string.md#stringisalpha) 132 | * [string.isNumeric](pages/string.md#stringisnumeric) 133 | * [string.isPunctuation](pages/string.md#stringispunctuation) 134 | * [string.isWhitespace](pages/string.md#stringiswhitespace) 135 | * [string.lastField](pages/string.md#stringlastfield) 136 | * [string.lower](pages/string.md#stringlower) 137 | * [string.maxStringLength](pages/string.md#stringmaxstringlength) 138 | * [string.markdownProcess](pages/string.md#stringmarkdownprocess) 139 | * [string.mid](pages/string.md#stringmid) 140 | * [string.monthToString](pages/string.md#stringmonthtostring) 141 | * [string.multipleReplaceAll](pages/string.md#stringmultiplereplaceall) 142 | * [string.nthField](pages/string.md#stringnthfield) 143 | * [string.padWithZeros](pages/string.md#stringpadwithzeros) 144 | * [string.popExtension](pages/string.md#stringpopextension) 145 | * [string.popLastField](pages/string.md#stringpoplastfield) 146 | * [string.popTrailing](pages/string.md#stringpoptrailing) 147 | * [string.randomSnarkySlogan](pages/string.md#stringrandomsnarkyslogan) 148 | * [string.replaceAll](pages/string.md#stringreplaceall) 149 | * [string.stripMarkup](pages/string.md#stringstripmarkup) 150 | * [string.trimLeading](pages/string.md#stringtrimleading) 151 | * [string.trimTrailing](pages/string.md#stringtrimtrailing) 152 | * [string.trimWhitespace](pages/string.md#stringtrimwhitespace) 153 | * [string.upper](pages/string.md#stringupper) 154 | * [tab.getActiveTabStatus](pages/tab.md#) 155 | * [tab.getPublicUrl](pages/tab.md#tabgetpublicurl) 156 | * [tab.openFile](pages/tab.md#tabopenfile) 157 | * [tab.openInstantOutline](pages/tab.md#tabopeninstantoutline) 158 | * [twitter.addGroupToList](pages/twitter.md#) 159 | * [twitter.addMemberToList](pages/twitter.md#) 160 | * [twitter.getFollowed](pages/twitter.md#twittergetfollowed) 161 | * [twitter.getFollowers](pages/twitter.md#) 162 | * [twitter.getHomeTimeline](pages/twitter.md#) 163 | * [twitter.getListInfo](pages/twitter.md#) 164 | * [twitter.getListMembers](pages/twitter.md#) 165 | * [twitter.getMentionsTimeline](pages/twitter.md#) 166 | * [twitter.getMyScreenname](pages/twitter.md#) 167 | * [twitter.getRawUserInfo](pages/twitter.md#) 168 | * [twitter.getScreenname](pages/twitter.md#) 169 | * [twitter.getThread](pages/twitter.md#) 170 | * [twitter.getTweet](pages/twitter.md#) 171 | * [twitter.getUserLists](pages/twitter.md#) 172 | * [twitter.getUserInfo](pages/twitter.md#) 173 | * [twitter.getUserTimeline](pages/twitter.md#) 174 | * [twitter.newPost](pages/twitter.md#) 175 | * [twitter.removeGroupFromList](pages/twitter.md#) 176 | * [twitter.removeUserFromList](pages/twitter.md#) 177 | * [twitter.updateListInfo](pages/twitter.md#) 178 | * [webBrowser.openUrl](pages/webBrowser.md#webbrowseropenurl) 179 | -------------------------------------------------------------------------------- /docs/pages/file.md: -------------------------------------------------------------------------------- 1 | 2 | # file verbs 3 | ## file.exists 4 | #### Syntax 5 | file.exists (path) 6 | 7 | #### Params 8 | path points to a file in the remote file system. 9 | 10 | #### Action 11 | Determines if the file exists 12 | 13 | #### Returns 14 | True if it exists, false otherwise 15 | 16 | #### Notes 17 | If you try to read a file that doesn't exist, for example, your script will fail. If your application can work even if a file doesn't exist, then you should use this verb to see if it exists. 18 | 19 | #### Examples 20 | `file.exists ("prefs.json")` 21 | 22 | `file.exists ("meaningOfLife.js")` 23 | 24 | ## file.writeWholeFile 25 | #### Syntax 26 | file.writeWholeFile (path, text) 27 | 28 | #### What it does 29 | Creates a new private file, or overwrites an existing file, at the indicated path, with the contents of the second parameter. It creates any folders needed to store the file if they don't exist. 30 | 31 | #### Returns 32 | true. 33 | 34 | #### Note 35 | Files are, by default, private. If you want to create a public file, first create the private file then call file.makeFilePublic. 36 | 37 | #### Examples 38 | `file.writeWholeFile ("hello.txt", "Hello World")` 39 | 40 | - *true* 41 | 42 | `file.writeWholeFile ("code/alert.js", "dialog.alert ('Yo')") ` 43 | 44 | - *true* 45 | 46 | ## file.readWholeFile 47 | #### Syntax 48 | file.readWholeFile (path) 49 | 50 | #### What it does 51 | Reads the file at the indicated path and returns its contents as a string. 52 | 53 | #### Returns 54 | The contents of the file, as a string. 55 | 56 | #### Example 57 | `file.readWholeFile ("hello.txt") ` 58 | 59 | - *Hello World* 60 | 61 | ## file.delete 62 | #### Syntax 63 | file.delete (path) 64 | 65 | #### What it does 66 | Tries to delete both a private file or a public one at the indicated path. It's an error if neither file exists. 67 | 68 | #### Returns 69 | undefined 70 | 71 | #### Example 72 | `file.writeWholeFile ("deleteme.txt", "It's even worse than it appears.")` 73 | 74 | - *true* 75 | 76 | `file.readWholeFile ("deleteme.txt")` 77 | 78 | - *It's even worse than it appears.* 79 | 80 | `file.delete ("deleteme.txt")` 81 | 82 | - *undefined* 83 | 84 | ## file.getFileInfo 85 | #### Syntax 86 | file.getFileInfo (path) 87 | 88 | #### Params 89 | path is a string, the location to a file being stored on the server. 90 | 91 | #### Returns 92 | Information about the file, including: its size in bytes, when it was created, last read, last modified, and whether it's public or private. 93 | 94 | If the file is public, urlPublic, the address of the file, is included. 95 | 96 | #### Example 97 | `file.getFileInfo ("states.opml") ` 98 | 99 |
{
100 |     "size": 2741,
101 |     "whenAccessed": "2021-08-24T14:51:15.000Z",
102 |     "whenCreated": "2021-08-24T14:51:15.000Z",
103 |     "whenModified": "2021-08-24T14:56:13.000Z",
104 |     "flPrivate": false,
105 |     "urlPublic": "http://drummer.scripting.com/cluelessnewbie/states.opml"
106 |     }
107 | 
108 | `file.getFileInfo ("scratchpad.opml")` 109 | 110 |
{
111 |     "size": 85332,
112 |     "whenAccessed": "2021-08-24T14:48:53.000Z",
113 |     "whenCreated": "2021-07-30T13:35:09.000Z",
114 |     "whenModified": "2021-08-24T14:58:31.000Z",
115 |     "flPrivate": true
116 |     }
117 | 
118 | ## file.makeFilePublic 119 | #### Syntax 120 | file.makeFilePublic (path) 121 | 122 | #### What it does 123 | Makes the file public if it is private. 124 | 125 | #### Returns 126 | The public URL of the file. 127 | 128 | #### Example 129 | `file.makeFilePublic ("hello.txt")` 130 | 131 | - *http://drummer.scripting.com/davewiner/hello.txt* 132 | 133 | `http.readUrl ("http://drummer.scripting.com/davewiner/hello.txt")` 134 | 135 | - *Hello World* 136 | 137 | ## file.getFileHierarchy 138 | #### Syntax 139 | file.getFileHierarchy () 140 | 141 | #### What it does 142 | Returns a JavaScript object that describes the user's file hierarchy. 143 | 144 | There are two top-level branches, Private files and Public files. Unless you have explicitly made a file public, all files are private. 145 | 146 | Under each is the hierarchy, as they are stored in the file system on the server. For each folder there is a whenCreated and a whenModified value, and an object called subs, which contains the files and any sub-folders. 147 | 148 | For each file, in addition to creation and modification dates, ctChars is the size of the file. 149 | 150 | #### Returns 151 | A JavaScript object as explained above. 152 | 153 | #### Notes 154 | This feature is based on the folderToJson package. 155 | 156 | And the Outline file hierarchy command in the Tools menu is built on file.getFileHierarchy. 157 | 158 | #### Example 159 | `file.getFileHierarchy ()` 160 | 161 |
{
162 |     "publicFiles": {
163 |         "subs": {
164 |             "april2021Status.opml": {
165 |                 "ctChars": 21475,
166 |                 "whenCreated": "2021-05-17T01:46:17.385Z",
167 |                 "whenModified": "2021-05-17T01:46:17.385Z"
168 |                 },
169 |             "aprilMayDrummerChanges.opml": {
170 |                 "ctChars": 15657,
171 |                 "whenCreated": "2021-05-17T01:40:27.646Z",
172 |                 "whenModified": "2021-05-17T01:41:56.446Z"
173 |                 },
174 |             "daveStatus.opml": {
175 |                 "ctChars": 39467,
176 |                 "whenCreated": "2021-05-06T22:34:17.160Z",
177 |                 "whenModified": "2021-05-29T16:13:19.181Z"
178 |                 },
179 |             "february2021Status.opml": {
180 |                 "ctChars": 70491,
181 |                 "whenCreated": "2021-05-17T01:43:24.202Z",
182 |                 "whenModified": "2021-05-17T01:43:24.202Z"
183 |                 },
184 |             "hello.txt": {
185 |                 "ctChars": 11,
186 |                 "whenCreated": "2021-05-29T16:08:07.954Z",
187 |                 "whenModified": "2021-05-29T16:12:06.257Z"
188 |                 },
189 |             "march2021Status.opml": {
190 |                 "ctChars": 51300,
191 |                 "whenCreated": "2021-05-17T01:45:09.122Z",
192 |                 "whenModified": "2021-05-17T01:45:09.298Z"
193 |                 },
194 |             "opVerbDocs.opml": {
195 |                 "ctChars": 56658,
196 |                 "whenCreated": "2021-05-16T19:39:17.747Z",
197 |                 "whenModified": "2021-05-17T01:38:28.054Z"
198 |                 },
199 |             "scratchpad.json": {
200 |                 "ctChars": 14558,
201 |                 "whenCreated": "2021-05-28T15:16:10.378Z",
202 |                 "whenModified": "2021-05-29T15:05:52.017Z"
203 |                 },
204 |             "scratchpad.opml": {
205 |                 "ctChars": 7290,
206 |                 "whenCreated": "2021-05-28T15:16:10.330Z",
207 |                 "whenModified": "2021-05-29T15:05:51.973Z"
208 |                 },
209 |             "twitterVerbDocs.json": {
210 |                 "ctChars": 135024,
211 |                 "whenCreated": "2021-05-28T16:16:08.924Z",
212 |                 "whenModified": "2021-05-28T18:10:22.472Z"
213 |                 },
214 |             "twitterVerbDocs.opml": {
215 |                 "ctChars": 51601,
216 |                 "whenCreated": "2021-05-07T15:03:13.106Z",
217 |                 "whenModified": "2021-05-28T18:10:22.296Z"
218 |                 },
219 |             "undefined": {
220 |                 "ctChars": 5491,
221 |                 "whenCreated": "2021-05-15T15:12:46.388Z",
222 |                 "whenModified": "2021-05-28T15:51:14.558Z"
223 |                 },
224 |             "verbDocs.opml": {
225 |                 "ctChars": 111226,
226 |                 "whenCreated": "2021-05-07T20:15:45.464Z",
227 |                 "whenModified": "2021-05-17T01:38:45.546Z"
228 |                 }
229 |             }
230 |         },
231 |     "privateFiles": {
232 |         "subs": {
233 |             "april2021Status.opml": {
234 |                 "ctChars": 21475,
235 |                 "whenCreated": "2021-05-17T01:45:58.182Z",
236 |                 "whenModified": "2021-05-17T01:46:14.309Z"
237 |                 },
238 |             "aprilMayDrummerChanges.opml": {
239 |                 "ctChars": 15768,
240 |                 "whenCreated": "2021-05-17T01:39:31.950Z",
241 |                 "whenModified": "2021-05-17T01:40:20.062Z"
242 |                 },
243 |             "bookmarks.opml": {
244 |                 "ctChars": 2476,
245 |                 "whenCreated": "2021-04-23T16:09:01.205Z",
246 |                 "whenModified": "2021-05-07T15:04:19.598Z"
247 |                 },
248 |             "daveStatus.opml": {
249 |                 "ctChars": 145031,
250 |                 "whenCreated": "2021-05-06T14:12:18.230Z",
251 |                 "whenModified": "2021-05-06T14:14:15.445Z"
252 |                 },
253 |             "dontlooknow.opml": {
254 |                 "ctChars": 1042,
255 |                 "whenCreated": "2021-04-23T16:11:49.568Z",
256 |                 "whenModified": "2021-04-23T16:12:55.524Z"
257 |                 },
258 |             "drummerDocs.opml": {
259 |                 "ctChars": 5570,
260 |                 "whenCreated": "2021-05-06T14:16:40.037Z",
261 |                 "whenModified": "2021-05-17T01:53:08.393Z"
262 |                 },
263 |             "february2021Status.opml": {
264 |                 "ctChars": 70491,
265 |                 "whenCreated": "2021-05-17T01:42:57.610Z",
266 |                 "whenModified": "2021-05-17T01:43:16.802Z"
267 |                 },
268 |             "hello.txt": {
269 |                 "ctChars": 11,
270 |                 "whenCreated": "2021-05-29T15:10:36.809Z",
271 |                 "whenModified": "2021-05-29T16:07:56.474Z"
272 |                 },
273 |             "march2021Status.opml": {
274 |                 "ctChars": 51300,
275 |                 "whenCreated": "2021-05-17T01:44:51.166Z",
276 |                 "whenModified": "2021-05-17T01:45:04.350Z"
277 |                 },
278 |             "menubar.opml": {
279 |                 "ctChars": 18704,
280 |                 "whenCreated": "2021-05-06T14:19:03.385Z",
281 |                 "whenModified": "2021-05-06T14:19:23.521Z"
282 |                 },
283 |             "notes.opml": {
284 |                 "ctChars": 1855,
285 |                 "whenCreated": "2021-04-23T16:08:23.549Z",
286 |                 "whenModified": "2021-05-04T15:01:57.487Z"
287 |                 },
288 |             "opVerbDocs.opml": {
289 |                 "ctChars": 53897,
290 |                 "whenCreated": "2021-05-06T14:15:20.717Z",
291 |                 "whenModified": "2021-05-06T14:15:21.000Z"
292 |                 },
293 |             "opVisitVerbs.opml": {
294 |                 "ctChars": 3056,
295 |                 "whenCreated": "2021-05-06T14:25:16.792Z",
296 |                 "whenModified": "2021-05-06T14:25:17.000Z"
297 |                 },
298 |             "prefs.json": {
299 |                 "ctChars": 3652,
300 |                 "whenCreated": "2021-04-23T16:08:24.389Z",
301 |                 "whenModified": "2021-05-29T16:13:20.017Z"
302 |                 },
303 |             "scheduler.opml": {
304 |                 "ctChars": 305,
305 |                 "whenCreated": "2021-05-28T13:53:08.393Z",
306 |                 "whenModified": "2021-05-28T13:53:08.393Z"
307 |                 },
308 |             "scratchpad.opml": {
309 |                 "ctChars": 4129,
310 |                 "whenCreated": "2021-05-06T14:23:30.457Z",
311 |                 "whenModified": "2021-05-28T18:07:38.836Z"
312 |                 },
313 |             "states.opml": {
314 |                 "ctChars": 6997,
315 |                 "whenCreated": "2021-05-06T14:24:16.656Z",
316 |                 "whenModified": "2021-05-19T20:34:00.863Z"
317 |                 },
318 |             "storage.json": {
319 |                 "ctChars": 2,
320 |                 "whenCreated": "2021-04-23T16:08:24.389Z",
321 |                 "whenModified": "2021-04-23T16:08:24.389Z"
322 |                 },
323 |             "todo.opml": {
324 |                 "ctChars": 13430,
325 |                 "whenCreated": "2021-05-06T14:06:02.714Z",
326 |                 "whenModified": "2021-05-21T16:33:25.355Z"
327 |                 },
328 |             "twitterVerbDocs.opml": {
329 |                 "ctChars": 21277,
330 |                 "whenCreated": "2021-05-07T15:02:51.782Z",
331 |                 "whenModified": "2021-05-07T15:03:06.890Z"
332 |                 },
333 |             "verbDocs.opml": {
334 |                 "ctChars": 186145,
335 |                 "whenCreated": "2021-05-06T14:15:21.481Z",
336 |                 "whenModified": "2021-05-07T15:04:04.578Z"
337 |                 }
338 |             }
339 |         }
340 |     }
341 | 
342 | `console.log (jsonStringify (file.getFileHierarchy ()))` 343 | 344 | - *undefined* 345 | 346 | -------------------------------------------------------------------------------- /webapp/code.js: -------------------------------------------------------------------------------- 1 | var myVersion = "0.4.4", myProductName = "DocServer"; 2 | 3 | var urlDocsOpml = "https://drummer.land/dave.winer@gmail.com/verbDocs.opml"; 4 | var docserverOpmltext = undefined; 5 | var docserverOutline = undefined; 6 | var urlUpdateSocket = undefined; 7 | var socketForChanges = undefined; 8 | var verbArray = undefined; 9 | var randomMysteryString; //7/7/21 by DW 10 | 11 | var appPrefs = { 12 | lastVerbViewed: "file.exists", 13 | ixcursor: 0, //index into the verb array 14 | catcursor: 0 //index into categories -- docserverOutline.subs 15 | } 16 | var flPrefsChanged = false; 17 | 18 | function xmlReadFile (url) { //a synchronous file read 19 | var urlReadFileApi = "https://httpproxy.scripting.com/httpReadUrl"; 20 | return ($.ajax ({ 21 | url: urlReadFileApi + "?url=" + encodeURIComponent (url) + "&type=" + encodeURIComponent ("text/plain"), 22 | headers: {"Accept": "text/x-opml"}, 23 | async: false, 24 | dataType: "text" , 25 | timeout: 30000 26 | }).responseText); 27 | } 28 | 29 | function xmlExpandIncludes (adrx, callback) { 30 | xmlExpandInclude (adrx); 31 | if (xmlHasSubs (adrx)) { 32 | $(adrx).children ("outline").each (function () { 33 | xmlExpandIncludes (this); 34 | }); 35 | } 36 | if (callback !== undefined) { 37 | callback (); 38 | } 39 | } 40 | function findInVerbArray (verbName) { 41 | verbName = stringLower (verbName); //unicase search 42 | for (var i = 0; i < verbArray.length; i++) { 43 | var theVerb = verbArray [i]; 44 | if (stringLower (theVerb.title) == verbName) { 45 | return (theVerb); 46 | } 47 | } 48 | return (undefined); 49 | } 50 | function redirectToDocserverPage (verbname) { //8/9/21 by DW 51 | var url = stringNthField (stringNthField (window.location.href, "?", 1), "#", 1); 52 | url += "?verb=" + verbname; 53 | window.open (url); 54 | } 55 | function buildVerbsMenu (theOutline, idMenuToInsertAfter) { 56 | var theMenu = $("#idVerbsMenuList"); 57 | theMenu.empty (); 58 | theOutline.subs.forEach (function (item, ix) { 59 | var liSubMenuItem = $("
  • " + item.text + "
  • "); 60 | var ulSubMenu = $(""); 61 | liSubMenuItem.append (ulSubMenu); 62 | theMenu.append (liSubMenuItem); 63 | item.subs.forEach (function (item, ix) { 64 | var liMenuItem = $("
  • "); 65 | var menuItemNameLink = $(""); 66 | menuItemNameLink.html (item.text); 67 | menuItemNameLink.click (function (event) { 68 | event.preventDefault (); 69 | console.log ("You chose this verb from the menu: " + item.text); 70 | redirectToDocserverPage (item.text); //8/9/21 by DW 71 | }); 72 | liMenuItem.append (menuItemNameLink); 73 | ulSubMenu.append (liMenuItem); 74 | }); 75 | }); 76 | } 77 | 78 | function prefsChanged () { 79 | flPrefsChanged = true; 80 | } 81 | function loadPrefs () { 82 | if (localStorage.docserverPrefs !== undefined) { 83 | try { 84 | var jstruct = JSON.parse (localStorage.docserverPrefs); 85 | for (var x in jstruct) { 86 | appPrefs [x] = jstruct [x]; 87 | } 88 | } 89 | catch (err) { 90 | } 91 | } 92 | } 93 | function shareCommand () { 94 | redirectToDocserverPage (verbArray [appPrefs.ixcursor].path); 95 | } 96 | function readOpmlFile (urlOutline, callback) { 97 | readHttpFile (urlOutline, function (opmltext) { 98 | if (opmltext === undefined) { 99 | callback ({message: "Can't read the OPML file containing the docs."}); 100 | } 101 | else { 102 | callback (undefined, opmltext); 103 | } 104 | }); 105 | } 106 | function wsWatchForChange () { //requests notification of changes to docserver opml file 107 | if (socketForChanges === undefined) { 108 | var theSocket = new WebSocket (urlUpdateSocket); 109 | socketForChanges = theSocket; //set global 110 | theSocket.onopen = function (evt) { 111 | var msg = "watch " + urlDocsOpml; 112 | console.log ("sending: \"" + msg + "\""); 113 | theSocket.send (msg); 114 | }; 115 | theSocket.onmessage = function (evt) { 116 | var s = evt.data; 117 | if (s !== undefined) { //no error 118 | var updatekey = "update\r"; 119 | if (beginsWith (s, updatekey)) { //it's an update 120 | s = stringDelete (s, 1, updatekey.length); 121 | 122 | if (s [0] == "\"") { //work around bug in daveappserver, its jsonifying a string, in notifySocketSubscribers 123 | s = stringDelete (s, 1, 1); 124 | s = stringDelete (s, s.length, 1) 125 | } 126 | 127 | console.log ("wsWatchForChange, " + new Date ().toLocaleTimeString () + ": update received, s.length == " + s.length); 128 | 129 | readOpmlFile (urlDocsOpml, function (err, opmltext) { 130 | if (err) { 131 | } 132 | else { 133 | rebootDocserver (opmltext); 134 | } 135 | }); 136 | } 137 | } 138 | }; 139 | theSocket.onclose = function (evt) { 140 | console.log ("tab.myChatLogSocket was closed."); 141 | socketForChanges = undefined; 142 | }; 143 | theSocket.onerror = function (evt) { 144 | console.log ("socketForChanges received an error"); 145 | }; 146 | } 147 | } 148 | function findFirstVerbInCategory (theCategory) { 149 | var catname = stringNthField (theCategory, " ", 1); 150 | for (var i = 0; i < verbArray.length; i++) { 151 | var item = verbArray [i]; 152 | if (beginsWith (item.title, catname)) { 153 | return (item); 154 | } 155 | } 156 | return (undefined); 157 | } 158 | function viewIndexOutline () { 159 | var theIndex = $("
    "); 160 | var theList = $(""); 161 | docserverOutline.subs.forEach (function (cat, ix) { 162 | var theClass = (ix == appPrefs.catcursor) ? " class=\"liCursor\" " : ""; 163 | var theItem = $("" + cat.text + ""); 164 | $(theItem).click (function () { 165 | var verb = findFirstVerbInCategory (cat.text); 166 | console.log (verb.path); 167 | viewDocserverPage (verb); 168 | appPrefs.catcursor = ix; 169 | viewIndexOutline (); 170 | }); 171 | $(theList).append (theItem); 172 | }); 173 | $(theIndex).append (theList); 174 | $("#idIndexPanel").empty (); 175 | $("#idIndexPanel").append (theIndex); 176 | } 177 | function moveCursorTo (ixInArray) { 178 | appPrefs.ixcursor = ixInArray; 179 | prefsChanged (); 180 | viewIndexOutline (); 181 | var cat = docserverOutline.subs [ixInArray]; 182 | viewDocserverPage (findFirstVerbInCategory (cat.text)); 183 | } 184 | function moveCursorUp () { 185 | if (appPrefs.ixcursor <= 0) { 186 | speakerBeep (); 187 | } 188 | else { 189 | moveCursorTo (appPrefs.ixcursor - 1); 190 | } 191 | } 192 | function moveCursorDown () { 193 | if (appPrefs.ixcursor >= docserverOutline.subs.length - 1) { 194 | speakerBeep (); 195 | } 196 | else { 197 | moveCursorTo (appPrefs.ixcursor + 1); 198 | } 199 | } 200 | function getVerbArray () { 201 | var theArray = new Array (); 202 | docserverOutline.subs.forEach (function (cat) { 203 | cat.subs.forEach (function (verbOutline) { 204 | var cattext = stringLower (replaceAll (stringNthField (cat.text, " ", 1), " ", "")); 205 | var verbtext = stringLower (replaceAll (stringNthField (verbOutline.text, " ", 1), ".", "")); 206 | var title = stringNthField (verbOutline.text, " ", 1); 207 | var path = replaceAll (title, ".", "/"); 208 | theArray.push ({ 209 | title, 210 | path: title, 211 | outline: verbOutline, 212 | ix: theArray.length 213 | }); 214 | }); 215 | }); 216 | return (theArray); 217 | } 218 | function findPageInOutline (theOutline, path, callback) { 219 | for (var i = 0; i < verbArray.length; i++) { 220 | var verb = verbArray [i]; 221 | if (path == verb.path) { 222 | appPrefs.ixcursor = i; 223 | prefsChanged (); 224 | callback (undefined, verb); 225 | return; 226 | } 227 | } 228 | callback ({message: "Couldn't display the page because the verb, \"" + path + "\" could not be found."}); 229 | } 230 | function viewDocserverPage (verb) { 231 | var theDocserverPage = $("
    "); 232 | function getNavLinks () { 233 | var theNavLinks = $("
    "); 234 | function addlink (ix, align) { 235 | var linkedverb = verbArray [ix]; 236 | if (linkedverb !== undefined) { 237 | var path = linkedverb.path; 238 | var title = linkedverb.title; //should be title 239 | var icon = ""; 240 | var text = (align == "left") ? icon + " " + title : title + " " + icon; 241 | var theLink = $("
    " + text + "
    "); 242 | $(theLink).click (function () { 243 | $(theLink).blur (); //take the focus off the link 244 | viewPageViaPath (path); 245 | viewIndexOutline (); 246 | }); 247 | return (theLink); 248 | } 249 | else { 250 | var theLink = $("
     
    "); 251 | return (theLink); 252 | } 253 | } 254 | 255 | $(theNavLinks).append (addlink (verb.ix + 1, "right")); 256 | $(theNavLinks).append (addlink (verb.ix - 1, "left")); 257 | 258 | 259 | $(theNavLinks).append ("
    " + verb.outline.text + "
    "); 264 | $(theDocserverPage).append ("
    "); 267 | verb.outline.subs.forEach (function (item) { 268 | var theSection = $("
    "); 269 | $(theSection).append ("
    " + item.text + "
    "); 270 | var sectionText = $("
    "); 271 | function appendPgfHierarchy (pgf, appendTo, fltoplevel) { 272 | var isComment = (pgf.isComment) ? " isComment " : ""; 273 | var myClass = " class=\"dsSectionPgf" + isComment + "\" "; 274 | var thisPgf = (fltoplevel) ? $("" + pgf.text + "

    ") : $("" + pgf.text + ""); 275 | $(appendTo).append (thisPgf); 276 | if (pgf.subs !== undefined) { 277 | var ul = $("
      "); 278 | $(thisPgf).append (ul); 279 | pgf.subs.forEach (function (item) { 280 | appendPgfHierarchy (item, ul, false); 281 | }); 282 | } 283 | } 284 | item.subs.forEach (function (item) { 285 | appendPgfHierarchy (item, sectionText, true); 286 | }); 287 | $(theSection).append (sectionText); 288 | $(docserverBody).append (theSection); 289 | }); 290 | 291 | $(theDocserverPage).append (docserverBody); 292 | $("#idDocserverPanel").empty (); 293 | $("#idDocserverPanel").append (theDocserverPage); 294 | 295 | $("#idPageTitle").text (myProductName + ": " + verb.path); //7/27/21 by DW 296 | 297 | appPrefs.lastVerbViewed = verb.path; 298 | prefsChanged (); 299 | hitCounter (); //11/28/21 by DW 300 | } 301 | function viewPageViaPath (path) { 302 | findPageInOutline (docserverOutline, path, function (err, verb) { 303 | if (err) { 304 | viewDocserverPage (verbArray [0]); 305 | appPrefs.ixcursor = 0; 306 | console.log (err.message); 307 | } 308 | else { 309 | viewDocserverPage (verb); 310 | } 311 | }); 312 | } 313 | function handleKeystroke (ev) { 314 | var whichKey = ev.which; 315 | 316 | console.log ("handleKeystroke: ev.which == " + ev.which + ", ev.metaKey == " + ev.metaKey + ", ev.ctrlKey == " + ev.ctrlKey); 317 | if (ev.metaKey || ev.ctrlKey) { //not consumed -- 9/25/20 by DW 318 | return (false); 319 | } 320 | 321 | switch (whichKey) { 322 | case 38: //up arrow 323 | moveCursorUp (); 324 | return (true); 325 | case 40: //down arrow 326 | moveCursorDown (); 327 | return (true); 328 | } 329 | return (false); //not consumed 330 | } 331 | function everyMinute () { 332 | var now = new Date (); 333 | if (now.getMinutes () == 0) { 334 | console.log ("\n" + myProductName + ": " + now.toLocaleTimeString () + ", v" + myVersion + "."); 335 | } 336 | } 337 | function everySecond () { 338 | wsWatchForChange (); 339 | if (flPrefsChanged) { 340 | var jsontext = jsonStringify (appPrefs); 341 | flPrefsChanged = false; 342 | localStorage.docserverPrefs = jsontext; 343 | } 344 | //if another copy of DocServer launched, we are not needed, we quit -- 7/7/21 by DW 345 | if (localStorage.docserverMysteryString !== undefined) { 346 | if (localStorage.docserverMysteryString != randomMysteryString) { 347 | window.location.href = "http://scripting.com/"; 348 | } 349 | } 350 | } 351 | function rebootDocserver (opmltext, pathparam, formatparam) { 352 | docserverOpmltext = opmltext; //set global 353 | var xstruct = xmlCompile (opmltext); 354 | var adrbody = getXstuctBody (xstruct); 355 | xmlExpandIncludes (adrbody, function () { //4/3/21 by DW 356 | var theOutline = outlineToJson (adrbody); 357 | docserverOutline = theOutline; //set global 358 | 359 | var adrhead = getXstuctHead (xstruct); 360 | urlUpdateSocket = xmlGetValue (adrhead, "urlUpdateSocket"); //set global 361 | 362 | verbArray = getVerbArray (); //set global 363 | 364 | if (pathparam !== undefined) { 365 | viewPageViaPath (pathparam); 366 | } 367 | else { 368 | viewPageViaPath (appPrefs.lastVerbViewed); 369 | } 370 | viewIndexOutline (); 371 | 372 | buildVerbsMenu (docserverOutline, "idMainMenu"); //4/8/21 by DW 373 | }); 374 | } 375 | function startup () { 376 | console.log ("startup"); 377 | //tell other copies of DocServer to quit -- 7/7/21 by DW 378 | randomMysteryString = getRandomPassword (25); 379 | localStorage.docserverMysteryString = randomMysteryString; 380 | loadPrefs (); 381 | $("#idVersionNumber").text (myProductName + " v" + myVersion); 382 | function finishStartup () { 383 | self.setInterval (everySecond, 1000); 384 | runEveryMinute (everyMinute); 385 | $("body").keydown (function (ev) { 386 | if (true) { //(!flModalInFront) { 387 | if (handleKeystroke (ev)) { 388 | ev.stopPropagation (); 389 | ev.preventDefault (); 390 | } 391 | } 392 | whenLastUserEvent = new Date (); 393 | }); 394 | } 395 | 396 | var urlparam = getURLParameter ("url"); //7/27/21 by DW 397 | if (urlparam != "null") { 398 | urlDocsOpml = urlparam; 399 | } 400 | 401 | 402 | readOpmlFile (urlDocsOpml, function (err, opmltext) { 403 | if (err) { 404 | alertDialog (err.message); 405 | } 406 | else { 407 | var pathparam = getURLParameter ("verb"); 408 | if (pathparam == "null") { 409 | pathparam = undefined; 410 | } 411 | rebootDocserver (opmltext, pathparam); 412 | finishStartup (); 413 | } 414 | }); 415 | } 416 | -------------------------------------------------------------------------------- /docs/pages/opml.md: -------------------------------------------------------------------------------- 1 | 2 | # opml verbs 3 | ## opml.parse 4 | #### Syntax 5 | opml.parse (string) 6 | 7 | #### Params 8 | The string is OPML text. 9 | 10 | #### What it does 11 | Parses the text and returns a standard JavaScript object representing the outline. 12 | 13 | #### Returns 14 | A JavaScript object representing the outline. 15 | 16 | #### Example 17 | `opml.parse (file.readWholeFile ("hello.opml"))` 18 | 19 |
      {
       20 |     "opml": {
       21 |         "head": {
       22 |             "title": "Hello World",
       23 |             "dateCreated": "Mon, 13 Sep 2021 21:30:28 GMT",
       24 |             "description": "A simple hello world outline.",
       25 |             "ownerTwitterScreenName": "cluelessnewbie",
       26 |             "ownerName": "Clueless Newbie",
       27 |             "ownerId": "http://twitter.com/cluelessnewbie",
       28 |             "urlUpdateSocket": "ws://drummer.scripting.com:1232/",
       29 |             "dateModified": "Mon, 13 Sep 2021 21:37:33 GMT",
       30 |             "expansionState": "1,2",
       31 |             "lastCursor": "3"
       32 |             },
       33 |         "body": {
       34 |             "subs": [
       35 |                 {
       36 |                     "text": "A few colors",
       37 |                     "created": "Mon, 13 Sep 2021 21:30:57 GMT",
       38 |                     "subs": [
       39 |                         {
       40 |                             "text": "Blues",
       41 |                             "created": "Mon, 13 Sep 2021 21:31:33 GMT",
       42 |                             "subs": [
       43 |                                 {
       44 |                                     "text": "Blue green",
       45 |                                     "created": "Mon, 13 Sep 2021 21:34:17 GMT"
       46 |                                     },
       47 |                                 {
       48 |                                     "text": "Light blue",
       49 |                                     "created": "Mon, 13 Sep 2021 21:34:52 GMT",
       50 |                                     "enclosure": "http://mp3.morningcoffeenotes.com/cn18Aug07.mp3",
       51 |                                     "enclosureType": "audio/mpeg",
       52 |                                     "enclosureLength": "6511738"
       53 |                                     },
       54 |                                 {
       55 |                                     "text": "Sky blue",
       56 |                                     "created": "Mon, 13 Sep 2021 21:34:20 GMT"
       57 |                                     }
       58 |                                 ]
       59 |                             },
       60 |                         {
       61 |                             "text": "Reds",
       62 |                             "created": "Mon, 13 Sep 2021 21:31:35 GMT",
       63 |                             "subs": [
       64 |                                 {
       65 |                                     "text": "Burnt sienna",
       66 |                                     "created": "Mon, 13 Sep 2021 21:34:57 GMT"
       67 |                                     },
       68 |                                 {
       69 |                                     "text": "Cherry",
       70 |                                     "created": "Mon, 13 Sep 2021 21:35:23 GMT"
       71 |                                     },
       72 |                                 {
       73 |                                     "text": "Persimmon",
       74 |                                     "created": "Mon, 13 Sep 2021 21:35:32 GMT",
       75 |                                     "type": "link",
       76 |                                     "url": "https://htmlcolorcodes.com/colors/persimmon/"
       77 |                                     }
       78 |                                 ]
       79 |                             },
       80 |                         {
       81 |                             "text": "Greens",
       82 |                             "created": "Mon, 13 Sep 2021 21:31:37 GMT",
       83 |                             "subs": [
       84 |                                 {
       85 |                                     "text": "Aqua",
       86 |                                     "created": "Mon, 13 Sep 2021 21:31:39 GMT"
       87 |                                     },
       88 |                                 {
       89 |                                     "text": "Cyan ",
       90 |                                     "created": "Mon, 13 Sep 2021 21:32:26 GMT"
       91 |                                     },
       92 |                                 {
       93 |                                     "text": "Pistachio",
       94 |                                     "created": "Mon, 13 Sep 2021 21:33:55 GMT"
       95 |                                     }
       96 |                                 ]
       97 |                             }
       98 |                         ]
       99 |                     }
      100 |                 ]
      101 |             }
      102 |         }
      103 |     }
      104 | 
      105 | ## opml.stringify 106 | #### Syntax 107 | opml.stringify (object) 108 | 109 | #### Params 110 | object is a JavaScript object representing an outline. 111 | 112 | #### Returns 113 | The OPML text for the object. 114 | 115 | #### Example 116 | `opml.stringify (opml.parse (file.readWholeFile ("hello.opml")))` 117 | 118 | - *<?xml version="1.0" encoding="ISO-8859-1"?>* 119 | 120 |
      <opml version="2.0">
      121 |     <head>
      122 |         <title>Hello World</title>
      123 |         <dateCreated>Mon, 13 Sep 2021 21:30:28 GMT</dateCreated>
      124 |         <description>A simple hello world outline, with a few subs.</description>
      125 |         <ownerTwitterScreenName>cluelessnewbie</ownerTwitterScreenName>
      126 |         <ownerName>Clueless Newbie</ownerName>
      127 |         <ownerId>http://twitter.com/cluelessnewbie</ownerId>
      128 |         <urlUpdateSocket>ws://drummer.scripting.com:1232/</urlUpdateSocket>
      129 |         <dateModified>Mon, 13 Sep 2021 21:37:33 GMT</dateModified>
      130 |         <expansionState>1,2</expansionState>
      131 |         <lastCursor>3</lastCursor>
      132 |         </head>
      133 |     <body>
      134 |         <outline text="A few colors" created="Mon, 13 Sep 2021 21:30:57 GMT" >
      135 |             <outline text="Blues" created="Mon, 13 Sep 2021 21:31:33 GMT" >
      136 |                 <outline text="Blue green" created="Mon, 13 Sep 2021 21:34:17 GMT" />
      137 |                 <outline text="Light blue" created="Mon, 13 Sep 2021 21:34:52 GMT" enclosure="http://mp3.morningcoffeenotes.com/cn18Aug07.mp3" enclosureType="audio/mpeg" enclosureLength="6511738" />
      138 |                 <outline text="Sky blue" created="Mon, 13 Sep 2021 21:34:20 GMT" />
      139 |                 </outline>
      140 |             <outline text="Reds" created="Mon, 13 Sep 2021 21:31:35 GMT" >
      141 |                 <outline text="Burnt sienna" created="Mon, 13 Sep 2021 21:34:57 GMT" />
      142 |                 <outline text="Cherry" created="Mon, 13 Sep 2021 21:35:23 GMT" />
      143 |                 <outline text="Persimmon" created="Mon, 13 Sep 2021 21:35:32 GMT" type="link" url="https://htmlcolorcodes.com/colors/persimmon/" />
      144 |                 </outline>
      145 |             <outline text="Greens" created="Mon, 13 Sep 2021 21:31:37 GMT" >
      146 |                 <outline text="Aqua" created="Mon, 13 Sep 2021 21:31:39 GMT" />
      147 |                 <outline text="Cyan " created="Mon, 13 Sep 2021 21:32:26 GMT" />
      148 |                 <outline text="Pistachio" created="Mon, 13 Sep 2021 21:33:55 GMT" />
      149 |                 </outline>
      150 |             </outline>
      151 |         </body>
      152 |     </opml>
      153 | 
      154 | ## opml.attributes.addGroup 155 | #### Syntax 156 | opml.attributes.addGroup (string, object) 157 | 158 | #### Params 159 | The string is the name of an OPML file in the user's Drummer account. 160 | 161 | The object is a collection of attributes in the form of a JavaScript object. 162 | 163 | #### What it does 164 | The value of the object replaces is added to the file-level attributes in the OPML file. 165 | 166 | Any previous attributes that are not in the object are not changed, and are still there. 167 | 168 | #### Returns 169 | The attributes of the file after the opml.attributes.setAll call. 170 | 171 | #### Example 172 | `opml.attributes.addGroup ("tmp.opml", {school: "Bronx Science", gpa: 3.5, major: "Art History"})` 173 | 174 |
      {
      175 |     "name": "Bjorn Barker",
      176 |     "age": "32",
      177 |     "school": "Bronx Science",
      178 |     "gpa": 3.5,
      179 |     "major": "Art History"
      180 |     }
      181 | 
      182 | ## opml.attributes.deleteOne 183 | #### Syntax 184 | opml.attributes.deleteOne (string, string) 185 | 186 | #### Params 187 | The first string is the name of an OPML file in the user's Drummer account. 188 | 189 | The second string is the name of an attribute. 190 | 191 | #### What it does 192 | Drummer deletes the named attribute in the file, if it exists. 193 | 194 | If the attribute doesn't exist, it is not an error. 195 | 196 | #### Returns 197 | The attributes of the file after the opml.attributes.deleteOne call. 198 | 199 | #### Example 200 | `opml.attributes.deleteOne ("tmp.opml", "height")` 201 | 202 |
      {
      203 |     "name": "Bjorn Barker",
      204 |     "age": "32"
      205 |     }
      206 | 
      207 | ## opml.attributes.exists 208 | #### Syntax 209 | opml.attributes.exists (string, string) 210 | 211 | #### Params 212 | The first string is the name of an OPML file in the user's Drummer account. 213 | 214 | The second string is the name of an attribute. 215 | 216 | #### Returns 217 | true if the attribute exists in the file, false otherwise. 218 | 219 | #### Examples 220 | `opml.attributes.exists ("tmp.opml", "major")` 221 | 222 | - *true* 223 | 224 | `opml.attributes.exists ("tmp.opml", "minor")` 225 | 226 | - *false* 227 | 228 | ## opml.attributes.getAll 229 | #### Syntax 230 | opml.attributes.getAll (string) 231 | 232 | #### Params 233 | The string is the name of an OPML file in the user's Drummer account. 234 | 235 | #### Returns 236 | All the elements of the <head> section of the OPML file for the outline. 237 | 238 | #### Example 239 | `opml.attributes.getAll ("scratchpad.opml")` 240 | 241 |
      {
      242 |     "title": "Scratchpad",
      243 |     "dateCreated": "Fri, 30 Jul 2021 13:35:09 GMT",
      244 |     "dateModified": "Mon, 06 Sep 2021 00:26:06 GMT",
      245 |     "ownerTwitterScreenName": "cluelessnewbie",
      246 |     "ownerName": "Clueless Newbie",
      247 |     "ownerId": "http://twitter.com/cluelessnewbie",
      248 |     "urlUpdateSocket": "ws://drummer.scripting.com:1232/",
      249 |     "expansionState": "1,2,4,6,15,16,21,23",
      250 |     "lastCursor": "2"
      251 |     }
      252 | 
      253 | ## opml.attributes.getOne 254 | #### Syntax 255 | opml.attributes.getOne (string, string) 256 | 257 | #### Params 258 | The first string is the name of an OPML file in the user's Drummer account. 259 | 260 | The second string is the name of an attribute. 261 | 262 | #### Returns 263 | The value of the named attribute. 264 | 265 | If the attribute doesn't exist, the value returned is the JavaScript value undefined. 266 | 267 | #### Example 268 | `opml.attributes.getOne ("tmp.opml", "name")` 269 | 270 | - *Bjorn Barker* 271 | 272 | `opml.attributes.getOne ("tmp.opml", "hometown")` 273 | 274 | - *undefined* 275 | 276 | ## opml.attributes.makeEmpty 277 | #### Syntax 278 | opml.attributes.makeEmpty (string) 279 | 280 | #### Params 281 | The first string is the name of an OPML file in the user's Drummer account. 282 | 283 | #### What it does 284 | Drummer deletes all the named attributes in the file. 285 | 286 | #### Returns 287 | The attributes of the file after the opml.attributes.deleteOne call. 288 | 289 | #### Example 290 | `opml.attributes.makeEmpty ("tmp.opml")` 291 | 292 | - *{ }* 293 | 294 | ## opml.attributes.setAll 295 | #### Syntax 296 | opml.attributes.setAll (string, object) 297 | 298 | #### Params 299 | The string is the name of an OPML file in the user's Drummer account. 300 | 301 | The object is a collection of attributes in the form of a JavaScript object. 302 | 303 | #### What it does 304 | The value of the object replaces all file-level attributes in the OPML file. 305 | 306 | The object should contain only name-value pairs. 307 | 308 | #### Returns 309 | The attributes of the file after the opml.attributes.setAll call. 310 | 311 | #### Example 312 | `opml.attributes.setAll ("tmp.opml", {name: "Bjorn Barker", age: 32})` 313 | 314 | - *true* 315 | 316 | ## opml.attributes.setOne 317 | #### Syntax 318 | opml.attributes.setOne (string, string, value) 319 | 320 | #### Params 321 | The first string is the name of an OPML file in the user's Drummer account. 322 | 323 | The second string is the name of an attribute. 324 | 325 | value is a JavaScript string, or a value that can be coerced to a string. 326 | 327 | #### What it does 328 | Drummer sets the value of the named attribute in the file. 329 | 330 | The attribute might exist, in which case its value is overwritten, or it is created. 331 | 332 | #### Returns 333 | The attributes of the file after the opml.attributes.setOne call. 334 | 335 | #### Example 336 | `opml.attributes.setOne ("tmp.opml", "height", 5.5 * 12)` 337 | 338 |
      {
      339 |     "name": "Bjorn Barker",
      340 |     "age": "32",
      341 |     "height": 66
      342 |     }
      343 | 
      344 | ## opml.getCurrentObject 345 | #### Syntax 346 | opml.getCurrentObject () 347 | 348 | #### Params 349 | None. 350 | 351 | #### Returns 352 | A JavaScript object with all the data contained in the current outline, accessible directly in JavaScript code. 353 | 354 | #### Note 355 | It does what opml.getCurrentOpml does, except instead of returning OPML text, it returns the same information as a JavaScript object. 356 | 357 | #### Example 358 | `opml.getCurrentObject ()` 359 | 360 |
      {
      361 |     "head": {
      362 |         "title": "test",
      363 |         "dateCreated": "Wed, 07 Apr 2021 16:05:20 GMT",
      364 |         "dateModified": "Wed, 07 Apr 2021 16:17:01 GMT"
      365 |         },
      366 |     "body": {
      367 |         "subs": [
      368 |             {
      369 |                 "text": "Hello World",
      370 |                 "created": "Wed, 07 Apr 2021 15:53:15 GMT"
      371 |                 }
      372 |             ]
      373 |         }
      374 |     }
      375 | 
      376 | ## opml.getCurrentOpml 377 | #### Syntax 378 | opml.getCurrentOpml () 379 | 380 | #### Params 381 | None. 382 | 383 | #### Returns 384 | The text returned is exactly what would be saved as OPML for the current outline. 385 | 386 | #### Example 387 | `opml.getCurrentOpml ()` 388 | 389 | - *<?xml version="1.0"?>* 390 | 391 |
      <opml version="2.0">
      392 |     <head>
      393 |         <title>A menu for meals</title>
      394 |         <dateCreated>Sat, 11 Sep 2021 14:40:49 GMT</dateCreated>
      395 |         <dateModified>Tue, 16 Nov 2021 21:20:48 GMT</dateModified>
      396 |         </head>
      397 |     <body>
      398 |         <outline text="Hello World" created="Tue, 16 Nov 2021 21:18:13 GMT">
      399 |             </outline>
      400 |         </body>
      401 |     </opml>
      402 | 
      403 | ## opml.getMarkdown 404 | #### Syntax 405 | opml.getMarkdown (opmltext) 406 | 407 | #### Params 408 | opmltext is a string containing text in OPML format. 409 | 410 | #### Returns 411 | The markdown-from-outline algorithm that was implemented in Old School. 412 | 413 | #### Notes 414 | This is markdown text for publishing, not for interop with outliners. 415 | 416 | We add two newlines at the end of the text of every outline node. 417 | 418 | We generate nothing for indentation, you can use that in your writing in any way that suits you. 419 | 420 | We respect the flSinglespaceMarkdown attribute. When it's present and true, we only add one newline for the subs. We also generate an extra newline at the end of the subs. 421 | 422 | #### Example 423 | `Here's the example outline:` 424 | 425 |
      Foods I like
      426 |     Cheese
      427 |     Bagels
      428 |         Everything
      429 |         Sesame
      430 |         Plain
      431 |     Sauces
      432 | 
      433 | `Bagels has a flSinglespaceMarkdown attribute with the value true.` 434 | 435 | `We ran this script.` 436 | 437 | - *console.log (opml.getMarkdown (op.getCursorOpml (false)))* 438 | 439 | `Which generated this text.` 440 | 441 | - *Cheese* 442 | 443 | - *
      * 444 | 445 | - *Bagels* 446 | 447 | - *
      * 448 | 449 | - *Everything* 450 | 451 | - *Sesame* 452 | 453 | - *Plain* 454 | 455 | - *
      * 456 | 457 | - *Sauces* 458 | 459 | ## opml.getHeaders 460 | #### Syntax 461 | opml.getHeaders () 462 | 463 | #### Params 464 | None. 465 | 466 | #### Returns 467 | All the elements of the <head> section of the OPML file for the current outline. 468 | 469 | #### Example 470 | `opml.getHeaders ()` 471 | 472 | - *{ "title": "verbDocs", "dateCreated": "Mon, 22 Mar 2021 16:14:46 GMT", "dateModified": "Wed, 07 Apr 2021 15:45:15 GMT", "expansionState": "5,6,7,9,11,13,17", "lastCursor": "13", "ownerTwitterScreenName": "davewiner", "ownerName": "Dave Winer", "ownerId": "http://twitter.com/davewiner", "urlUpdateSocket": "ws://test.littleoutliner.com:1230/", "longTitle": "", "description": "" }* 473 | 474 | ## opml.setHeaders 475 | #### Syntax 476 | opml.setHeaders (object) 477 | 478 | #### Params 479 | The parameter is a JavaScript object containing the new values for the <head> section of the OPML file for the current outline. 480 | 481 | #### Returns 482 | undefined. 483 | 484 | #### Notes 485 | The headers are not replaced by this call, it's additive. 486 | 487 | There is currently no way, from a script, to delete a head element. 488 | 489 | #### Example 490 | `var headers = opml.getHeaders ();` 491 | 492 | `headers.someRandomValue = number.random (1, 1000);` 493 | 494 | `opml.setHeaders (headers);` 495 | 496 | -------------------------------------------------------------------------------- /docs/pages/github.md: -------------------------------------------------------------------------------- 1 | 2 | # github verbs 3 | ## github.connectViaOauth 4 | #### Syntax 5 | github.connectViaOauth () 6 | 7 | #### Params 8 | None 9 | 10 | #### What it does 11 | Initiates an Oauth login with GitHub. 12 | 13 | When it's done, you will have an "access token" in local storage on the computer you're using. 14 | 15 | The access token allows you to use the other GitHub verbs. 16 | 17 | #### Note 18 | This verb does not work in Electric Drummer yet. But you can use the other GitHub verbs if you copy the access token from web Drummer into localStorage on the Electric Drummer. Here's a blog post that explains what to do step by step. 19 | 20 | #### Returns 21 | true 22 | 23 | #### Example 24 | `github.connectViaOauth ()` 25 | 26 | - *true* 27 | 28 | `localStorage.githubAccessToken //this is where you access token is stored` 29 | 30 | - *1234567890123456789012345678901234567890* 31 | 32 | ## github.disconnect 33 | #### Syntax 34 | github.disconnect () 35 | 36 | #### Params 37 | None 38 | 39 | #### What it does 40 | Removes the local access token, effectively logging you off GitHub. 41 | 42 | The GitHub verbs will not work on this machine after calling github.disconnect. 43 | 44 | #### Returns 45 | true 46 | 47 | #### Example 48 | `github.disconnect ()` 49 | 50 | - *true* 51 | 52 | ## github.download 53 | #### Syntax 54 | github.download (username, repository, path) 55 | 56 | #### Params 57 | The first two strings identify a GitHub repository. The first is the username, and the second is the name of the repository in the user's GitHub account. 58 | 59 | The third string is a path to the object you want to download. 60 | 61 | #### Returns 62 | A JavaScript object with information about the file, including its contents. 63 | 64 | #### Examples 65 | `base64.decode (github.download ("scripting", "Scripting-News", "/blog/stories/2020/02/15/a142106.md").content)` 66 | 67 | - *Questions for all Democratic candidates, esp Bloomberg. Do you feel the president is above the law? If you are elected, will you use the new powers Trump has taken for himself? What will you do if Trump refuses to leave?* 68 | 69 | `github.download ("scripting", "Scripting-News", "/blog/stories/2020/02/15/a142106.md").size` 70 | 71 | - *319* 72 | 73 | ## github.getAccessToken 74 | #### Syntax 75 | github.getAccessToken () 76 | 77 | #### Params 78 | None. 79 | 80 | #### Returns 81 | The access token if you're logged in, undefined if not. 82 | 83 | #### Example 84 | `github.getAccessToken ()` 85 | 86 | - *1234567890123456789012345678901234567890* 87 | 88 | ## github.getDirectory 89 | #### Syntax 90 | github.getDirectory (username, repository, path) 91 | 92 | #### Params 93 | The first two strings identify a GitHub repository. The first is the username, and the second is the name of the repository in the user's GitHub account. 94 | 95 | The third string is a path to the directory you want a list of. 96 | 97 | #### Returns 98 | A JavaScript object containing information about all the files in the directory. 99 | 100 | #### Examples 101 | `github.getDirectory ("scripting", "tmp1")` 102 | 103 |
      [
      104 |     {
      105 |         "name": "README.md",
      106 |         "path": "README.md",
      107 |         "sha": "449f080ed3d5eca1c16edfc0d14ed0851ee51a05",
      108 |         "size": 30,
      109 |         "url": "https://api.github.com/repos/scripting/tmp1/contents/README.md?ref=main",
      110 |         "html_url": "https://github.com/scripting/tmp1/blob/main/README.md",
      111 |         "git_url": "https://api.github.com/repos/scripting/tmp1/git/blobs/449f080ed3d5eca1c16edfc0d14ed0851ee51a05",
      112 |         "download_url": "https://raw.githubusercontent.com/scripting/tmp1/main/README.md",
      113 |         "type": "file",
      114 |         "_links": {
      115 |             "self": "https://api.github.com/repos/scripting/tmp1/contents/README.md?ref=main",
      116 |             "git": "https://api.github.com/repos/scripting/tmp1/git/blobs/449f080ed3d5eca1c16edfc0d14ed0851ee51a05",
      117 |             "html": "https://github.com/scripting/tmp1/blob/main/README.md"
      118 |             }
      119 |         },
      120 |     {
      121 |         "name": "andSheWas.opml",
      122 |         "path": "andSheWas.opml",
      123 |         "sha": "8197f7b204207b55b4e26fc292fe1b974c73406d",
      124 |         "size": 3233,
      125 |         "url": "https://api.github.com/repos/scripting/tmp1/contents/andSheWas.opml?ref=main",
      126 |         "html_url": "https://github.com/scripting/tmp1/blob/main/andSheWas.opml",
      127 |         "git_url": "https://api.github.com/repos/scripting/tmp1/git/blobs/8197f7b204207b55b4e26fc292fe1b974c73406d",
      128 |         "download_url": "https://raw.githubusercontent.com/scripting/tmp1/main/andSheWas.opml",
      129 |         "type": "file",
      130 |         "_links": {
      131 |             "self": "https://api.github.com/repos/scripting/tmp1/contents/andSheWas.opml?ref=main",
      132 |             "git": "https://api.github.com/repos/scripting/tmp1/git/blobs/8197f7b204207b55b4e26fc292fe1b974c73406d",
      133 |             "html": "https://github.com/scripting/tmp1/blob/main/andSheWas.opml"
      134 |             }
      135 |         },
      136 |     {
      137 |         "name": "buzz.md",
      138 |         "path": "buzz.md",
      139 |         "sha": "9f65b87f16ca67b8033b028be0c0bab35da5bd8f",
      140 |         "size": 30,
      141 |         "url": "https://api.github.com/repos/scripting/tmp1/contents/buzz.md?ref=main",
      142 |         "html_url": "https://github.com/scripting/tmp1/blob/main/buzz.md",
      143 |         "git_url": "https://api.github.com/repos/scripting/tmp1/git/blobs/9f65b87f16ca67b8033b028be0c0bab35da5bd8f",
      144 |         "download_url": "https://raw.githubusercontent.com/scripting/tmp1/main/buzz.md",
      145 |         "type": "file",
      146 |         "_links": {
      147 |             "self": "https://api.github.com/repos/scripting/tmp1/contents/buzz.md?ref=main",
      148 |             "git": "https://api.github.com/repos/scripting/tmp1/git/blobs/9f65b87f16ca67b8033b028be0c0bab35da5bd8f",
      149 |             "html": "https://github.com/scripting/tmp1/blob/main/buzz.md"
      150 |             }
      151 |         },
      152 |     {
      153 |         "name": "buzz.txt",
      154 |         "path": "buzz.txt",
      155 |         "sha": "b89a0f4ed3bc9334e0e39ccfeae06aebf3c213b9",
      156 |         "size": 26,
      157 |         "url": "https://api.github.com/repos/scripting/tmp1/contents/buzz.txt?ref=main",
      158 |         "html_url": "https://github.com/scripting/tmp1/blob/main/buzz.txt",
      159 |         "git_url": "https://api.github.com/repos/scripting/tmp1/git/blobs/b89a0f4ed3bc9334e0e39ccfeae06aebf3c213b9",
      160 |         "download_url": "https://raw.githubusercontent.com/scripting/tmp1/main/buzz.txt",
      161 |         "type": "file",
      162 |         "_links": {
      163 |             "self": "https://api.github.com/repos/scripting/tmp1/contents/buzz.txt?ref=main",
      164 |             "git": "https://api.github.com/repos/scripting/tmp1/git/blobs/b89a0f4ed3bc9334e0e39ccfeae06aebf3c213b9",
      165 |             "html": "https://github.com/scripting/tmp1/blob/main/buzz.txt"
      166 |             }
      167 |         },
      168 |     {
      169 |         "name": "menubar.opml",
      170 |         "path": "menubar.opml",
      171 |         "sha": "18f8da4953d764729d0250479435e61b83d4b972",
      172 |         "size": 1950,
      173 |         "url": "https://api.github.com/repos/scripting/tmp1/contents/menubar.opml?ref=main",
      174 |         "html_url": "https://github.com/scripting/tmp1/blob/main/menubar.opml",
      175 |         "git_url": "https://api.github.com/repos/scripting/tmp1/git/blobs/18f8da4953d764729d0250479435e61b83d4b972",
      176 |         "download_url": "https://raw.githubusercontent.com/scripting/tmp1/main/menubar.opml",
      177 |         "type": "file",
      178 |         "_links": {
      179 |             "self": "https://api.github.com/repos/scripting/tmp1/contents/menubar.opml?ref=main",
      180 |             "git": "https://api.github.com/repos/scripting/tmp1/git/blobs/18f8da4953d764729d0250479435e61b83d4b972",
      181 |             "html": "https://github.com/scripting/tmp1/blob/main/menubar.opml"
      182 |             }
      183 |         }
      184 |     ]
      185 | 
      186 | `github.getDirectory ("scripting", "Scripting-News", "/blog/opml/2017")` 187 | 188 |
      [
      189 |     {
      190 |         "name": "05.opml",
      191 |         "path": "blog/opml/2017/05.opml",
      192 |         "sha": "69cd335c1d713c37e136fc97b875072a24c92ea3",
      193 |         "size": 117772,
      194 |         "url": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/05.opml?ref=master",
      195 |         "html_url": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/05.opml",
      196 |         "git_url": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/69cd335c1d713c37e136fc97b875072a24c92ea3",
      197 |         "download_url": "https://raw.githubusercontent.com/scripting/Scripting-News/master/blog/opml/2017/05.opml",
      198 |         "type": "file",
      199 |         "_links": {
      200 |             "self": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/05.opml?ref=master",
      201 |             "git": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/69cd335c1d713c37e136fc97b875072a24c92ea3",
      202 |             "html": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/05.opml"
      203 |             }
      204 |         },
      205 |     {
      206 |         "name": "06.opml",
      207 |         "path": "blog/opml/2017/06.opml",
      208 |         "sha": "864439149998198cbebbd142b24d1d4cd71196f5",
      209 |         "size": 209566,
      210 |         "url": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/06.opml?ref=master",
      211 |         "html_url": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/06.opml",
      212 |         "git_url": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/864439149998198cbebbd142b24d1d4cd71196f5",
      213 |         "download_url": "https://raw.githubusercontent.com/scripting/Scripting-News/master/blog/opml/2017/06.opml",
      214 |         "type": "file",
      215 |         "_links": {
      216 |             "self": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/06.opml?ref=master",
      217 |             "git": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/864439149998198cbebbd142b24d1d4cd71196f5",
      218 |             "html": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/06.opml"
      219 |             }
      220 |         },
      221 |     {
      222 |         "name": "08.opml",
      223 |         "path": "blog/opml/2017/08.opml",
      224 |         "sha": "838e15184ae527659fd3273f89f3419a0f283ecd",
      225 |         "size": 134679,
      226 |         "url": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/08.opml?ref=master",
      227 |         "html_url": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/08.opml",
      228 |         "git_url": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/838e15184ae527659fd3273f89f3419a0f283ecd",
      229 |         "download_url": "https://raw.githubusercontent.com/scripting/Scripting-News/master/blog/opml/2017/08.opml",
      230 |         "type": "file",
      231 |         "_links": {
      232 |             "self": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/08.opml?ref=master",
      233 |             "git": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/838e15184ae527659fd3273f89f3419a0f283ecd",
      234 |             "html": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/08.opml"
      235 |             }
      236 |         },
      237 |     {
      238 |         "name": "09.opml",
      239 |         "path": "blog/opml/2017/09.opml",
      240 |         "sha": "f7c49b9358350b1174ee3199821ceab771618551",
      241 |         "size": 149136,
      242 |         "url": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/09.opml?ref=master",
      243 |         "html_url": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/09.opml",
      244 |         "git_url": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/f7c49b9358350b1174ee3199821ceab771618551",
      245 |         "download_url": "https://raw.githubusercontent.com/scripting/Scripting-News/master/blog/opml/2017/09.opml",
      246 |         "type": "file",
      247 |         "_links": {
      248 |             "self": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/09.opml?ref=master",
      249 |             "git": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/f7c49b9358350b1174ee3199821ceab771618551",
      250 |             "html": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/09.opml"
      251 |             }
      252 |         },
      253 |     {
      254 |         "name": "10.opml",
      255 |         "path": "blog/opml/2017/10.opml",
      256 |         "sha": "f05dd3581a93f26d8e972cecffb0c313e480e873",
      257 |         "size": 120405,
      258 |         "url": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/10.opml?ref=master",
      259 |         "html_url": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/10.opml",
      260 |         "git_url": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/f05dd3581a93f26d8e972cecffb0c313e480e873",
      261 |         "download_url": "https://raw.githubusercontent.com/scripting/Scripting-News/master/blog/opml/2017/10.opml",
      262 |         "type": "file",
      263 |         "_links": {
      264 |             "self": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/10.opml?ref=master",
      265 |             "git": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/f05dd3581a93f26d8e972cecffb0c313e480e873",
      266 |             "html": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/10.opml"
      267 |             }
      268 |         },
      269 |     {
      270 |         "name": "11.opml",
      271 |         "path": "blog/opml/2017/11.opml",
      272 |         "sha": "f06576fac10c3aedbf24a322df4df52ad046b9e9",
      273 |         "size": 114018,
      274 |         "url": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/11.opml?ref=master",
      275 |         "html_url": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/11.opml",
      276 |         "git_url": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/f06576fac10c3aedbf24a322df4df52ad046b9e9",
      277 |         "download_url": "https://raw.githubusercontent.com/scripting/Scripting-News/master/blog/opml/2017/11.opml",
      278 |         "type": "file",
      279 |         "_links": {
      280 |             "self": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/11.opml?ref=master",
      281 |             "git": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/f06576fac10c3aedbf24a322df4df52ad046b9e9",
      282 |             "html": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/11.opml"
      283 |             }
      284 |         },
      285 |     {
      286 |         "name": "12.opml",
      287 |         "path": "blog/opml/2017/12.opml",
      288 |         "sha": "a016cfe0146629d8f2b85003f9cf36e23ba43415",
      289 |         "size": 129193,
      290 |         "url": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/12.opml?ref=master",
      291 |         "html_url": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/12.opml",
      292 |         "git_url": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/a016cfe0146629d8f2b85003f9cf36e23ba43415",
      293 |         "download_url": "https://raw.githubusercontent.com/scripting/Scripting-News/master/blog/opml/2017/12.opml",
      294 |         "type": "file",
      295 |         "_links": {
      296 |             "self": "https://api.github.com/repos/scripting/Scripting-News/contents/blog/opml/2017/12.opml?ref=master",
      297 |             "git": "https://api.github.com/repos/scripting/Scripting-News/git/blobs/a016cfe0146629d8f2b85003f9cf36e23ba43415",
      298 |             "html": "https://github.com/scripting/Scripting-News/blob/master/blog/opml/2017/12.opml"
      299 |             }
      300 |         }
      301 |     ]
      302 | 
      303 | ## github.getUserInfo 304 | #### Syntax 305 | github.getUserInfo (string) 306 | 307 | #### Params 308 | The string, which is optional, is the username of the account you want the information of. 309 | 310 | #### Returns 311 | If the username is not provided, github.getUserInfo returns a JavaScript object containing the user info for the current logged-in user. 312 | 313 | #### Examples 314 | `github.getUserInfo ()` 315 | 316 |
      {
      317 |     "login": "scripting",
      318 |     "id": 1686843,
      319 |     "node_id": "MDQ6VXNlcjE2ODY4NDM=",
      320 |     "avatar_url": "https://avatars.githubusercontent.com/u/1686843?v=4",
      321 |     "gravatar_id": "",
      322 |     "url": "https://api.github.com/users/scripting",
      323 |     "html_url": "https://github.com/scripting",
      324 |     "followers_url": "https://api.github.com/users/scripting/followers",
      325 |     "following_url": "https://api.github.com/users/scripting/following{/other_user }",
      326 |     "gists_url": "https://api.github.com/users/scripting/gists{/gist_id }",
      327 |     "starred_url": "https://api.github.com/users/scripting/starred{/owner }{/repo }",
      328 |     "subscriptions_url": "https://api.github.com/users/scripting/subscriptions",
      329 |     "organizations_url": "https://api.github.com/users/scripting/orgs",
      330 |     "repos_url": "https://api.github.com/users/scripting/repos",
      331 |     "events_url": "https://api.github.com/users/scripting/events{/privacy }",
      332 |     "received_events_url": "https://api.github.com/users/scripting/received_events",
      333 |     "type": "User",
      334 |     "site_admin": false,
      335 |     "name": "Dave Winer",
      336 |     "company": "Small Picture, Inc.",
      337 |     "blog": "http://davewiner.com/",
      338 |     "location": "Woodstock, NY",
      339 |     "email": "dave.winer@gmail.com",
      340 |     "hireable": null,
      341 |     "bio": "On the net since mid-70s. Started two Silicon Valley companies. Wrote for Wired. Fellow at Harvard, NYU. Founder of podcasting, blogging, RSS. Open web.",
      342 |     "twitter_username": null,
      343 |     "public_repos": 130,
      344 |     "public_gists": 159,
      345 |     "followers": 704,
      346 |     "following": 49,
      347 |     "created_at": "2012-04-28T01:19:35Z",
      348 |     "updated_at": "2021-08-03T13:52:51Z"
      349 |     }
      350 | 
      351 | `github.getUserInfo ("octocat")` 352 | 353 |
      {
      354 |     "login": "octocat",
      355 |     "id": 583231,
      356 |     "node_id": "MDQ6VXNlcjU4MzIzMQ==",
      357 |     "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
      358 |     "gravatar_id": "",
      359 |     "url": "https://api.github.com/users/octocat",
      360 |     "html_url": "https://github.com/octocat",
      361 |     "followers_url": "https://api.github.com/users/octocat/followers",
      362 |     "following_url": "https://api.github.com/users/octocat/following{/other_user }",
      363 |     "gists_url": "https://api.github.com/users/octocat/gists{/gist_id }",
      364 |     "starred_url": "https://api.github.com/users/octocat/starred{/owner }{/repo }",
      365 |     "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
      366 |     "organizations_url": "https://api.github.com/users/octocat/orgs",
      367 |     "repos_url": "https://api.github.com/users/octocat/repos",
      368 |     "events_url": "https://api.github.com/users/octocat/events{/privacy }",
      369 |     "received_events_url": "https://api.github.com/users/octocat/received_events",
      370 |     "type": "User",
      371 |     "site_admin": false,
      372 |     "name": "The Octocat",
      373 |     "company": "@github",
      374 |     "blog": "https://github.blog",
      375 |     "location": "San Francisco",
      376 |     "email": "octocat@github.com",
      377 |     "hireable": null,
      378 |     "bio": null,
      379 |     "twitter_username": null,
      380 |     "public_repos": 8,
      381 |     "public_gists": 8,
      382 |     "followers": 4147,
      383 |     "following": 9,
      384 |     "created_at": "2011-01-25T18:44:36Z",
      385 |     "updated_at": "2021-10-22T14:27:39Z"
      386 |     }
      387 | 
      388 | ## github.upload 389 | #### Syntax 390 | github.upload (username, repository, path, data, message) 391 | 392 | #### Params 393 | The first two strings identify a GitHub repository. The first is the username, and the second is the name of the repository in the user's GitHub account. 394 | 395 | The third string is a path to the object you want to upload. 396 | 397 | The fourth string is the data of the file to be created by the upload. 398 | 399 | The fifth string is the "commit message" that is displayed next to the object in GitHub. It it is not supplied, the server generates a random slogan for the commit message. 400 | 401 | #### Returns 402 | All the information GitHub returns about the upload. 403 | 404 | #### Examples 405 | `github.upload ("scripting", "tmp1", "hello.txt", "Hello World")` 406 | 407 |
      {
      408 |     "content": {
      409 |         "name": "hello.txt",
      410 |         "path": "hello.txt",
      411 |         "sha": "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689",
      412 |         "size": 11,
      413 |         "url": "https://api.github.com/repos/scripting/tmp1/contents/hello.txt?ref=main",
      414 |         "html_url": "https://github.com/scripting/tmp1/blob/main/hello.txt",
      415 |         "git_url": "https://api.github.com/repos/scripting/tmp1/git/blobs/5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689",
      416 |         "download_url": "https://raw.githubusercontent.com/scripting/tmp1/main/hello.txt",
      417 |         "type": "file",
      418 |         "_links": {
      419 |             "self": "https://api.github.com/repos/scripting/tmp1/contents/hello.txt?ref=main",
      420 |             "git": "https://api.github.com/repos/scripting/tmp1/git/blobs/5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689",
      421 |             "html": "https://github.com/scripting/tmp1/blob/main/hello.txt"
      422 |             }
      423 |         },
      424 |     "commit": {
      425 |         "sha": "e0ef91110335af449223826acdc681988e441aad",
      426 |         "node_id": "C_kwDOGWnhedoAKGUwZWY5MTExMDMzNWFmNDQ5MjIzODI2YWNkYzY4MTk4OGU0NDFhYWQ",
      427 |         "url": "https://api.github.com/repos/scripting/tmp1/git/commits/e0ef91110335af449223826acdc681988e441aad",
      428 |         "html_url": "https://github.com/scripting/tmp1/commit/e0ef91110335af449223826acdc681988e441aad",
      429 |         "author": {
      430 |             "name": "Dave Winer",
      431 |             "email": "dave.winer@gmail.com",
      432 |             "date": "2021-11-10T20:52:18Z"
      433 |             },
      434 |         "committer": {
      435 |             "name": "Dave Winer",
      436 |             "email": "dave.winer@gmail.com",
      437 |             "date": "2021-11-10T20:52:18Z"
      438 |             },
      439 |         "tree": {
      440 |             "sha": "d225f272b14b41078d954bd7d7d75f85c876a66b",
      441 |             "url": "https://api.github.com/repos/scripting/tmp1/git/trees/d225f272b14b41078d954bd7d7d75f85c876a66b"
      442 |             },
      443 |         "message": "Takes a lickin, keeps on tickin.",
      444 |         "parents": [
      445 |             {
      446 |                 "sha": "7a6ac66cd728566fbe9bd10bc38882e6ff1f060a",
      447 |                 "url": "https://api.github.com/repos/scripting/tmp1/git/commits/7a6ac66cd728566fbe9bd10bc38882e6ff1f060a",
      448 |                 "html_url": "https://github.com/scripting/tmp1/commit/7a6ac66cd728566fbe9bd10bc38882e6ff1f060a"
      449 |                 }
      450 |             ],
      451 |         "verification": {
      452 |             "verified": false,
      453 |             "reason": "unsigned",
      454 |             "signature": null,
      455 |             "payload": null
      456 |             }
      457 |         },
      458 |     "statusCode": 201
      459 |     }
      460 | 
      461 | -------------------------------------------------------------------------------- /docs/pages/op.md: -------------------------------------------------------------------------------- 1 | 2 | # op verbs 3 | ## op.attributes.addGroup 4 | #### Syntax 5 | op.attributes.addGroup (object) 6 | 7 | #### Params 8 | The properties of the object parameter are added to the bar cursor headline. 9 | 10 | #### Returns 11 | The object. 12 | 13 | #### Example 14 | `op.attributes.addGroup ({age: 98, hair: "brown", location: "Minnesota"})` 15 | 16 |
      {
        17 |     "age": 98,
        18 |     "hair": "brown",
        19 |     "location": "Minnesota"
        20 |     }
        21 | 
      22 | ## op.attributes.deleteOne 23 | #### Syntax 24 | op.attributes.deleteOne (name) 25 | 26 | #### Params 27 | The string is the name of an attribute. 28 | 29 | #### What it does 30 | The attribute is deleted on the bar cursor headline, if it exists. 31 | 32 | #### Returns 33 | true if it deleted the att, false if it didn't. 34 | 35 | #### Example 36 | `op.attributes.deleteOne ("age")` 37 | 38 | - *false* 39 | 40 | `op.attributes.deleteOne ("location")` 41 | 42 | - *true* 43 | 44 | ## op.attributes.exists 45 | #### Syntax 46 | op.attributes.exists (string) 47 | 48 | #### Params 49 | The string is the name of an attribute. 50 | 51 | #### Returns 52 | If the attribute exists on the bar cursor headline it returns true, false otherwise. 53 | 54 | #### Example 55 | `op.attributes.exists ("created")` 56 | 57 | - *true* 58 | 59 | `op.attributes.exists ("mysteryAttribute")` 60 | 61 | - *false* 62 | 63 | ## op.attributes.getAll 64 | #### Syntax 65 | op.attributes.getAll () 66 | 67 | #### Params 68 | None. 69 | 70 | #### Returns 71 | A JavaScript object containing all the attributes attached to the bar cursor headline. 72 | 73 | #### Example 74 | `op.attributes.getAll ()` 75 | 76 |
      {
        77 |     "created": "Tue, 30 Mar 2021 16:07:59 GMT",
        78 |     "age": "32"
        79 |     }
        80 | 
      81 | ## op.attributes.getOne 82 | #### Syntax 83 | op.attributes.getOne (string) 84 | 85 | #### Params 86 | The string is the name of an attribute. 87 | 88 | #### Returns 89 | The value of the named attribute on the bar cursor headline. 90 | 91 | If the attribute doesn't exist, it returns undefined. 92 | 93 | #### Example 94 | `op.attributes.getOne ("created")` 95 | 96 | - *Tue, 30 Mar 2021 16:07:59 GMT* 97 | 98 | `op.attributes.getOne ("meaningOfLife")` 99 | 100 | - *undefined* 101 | 102 | ## op.attributes.makeEmpty 103 | #### Syntax 104 | op.attributes.makeEmpty () 105 | 106 | #### Params 107 | None. 108 | 109 | #### What it does 110 | Removes all the attributes of the bar cursor headline. 111 | 112 | #### Bug 113 | When we remove the created attribute, it is replaced automatically. Not clear where this is happening, but it probably shouldn't be doing this. 114 | 115 | #### Returns 116 | true. 117 | 118 | #### Example 119 | `op.attributes.makeEmpty ()` 120 | 121 | - *true* 122 | 123 | ## op.attributes.setOne 124 | #### Syntax 125 | op.attributes.setOne (name, val) 126 | 127 | #### Params 128 | Both params are strings. 129 | 130 | The first is the name of the attribute of the bar cursor headline that you want to set. 131 | 132 | The second is the value that will be assigned to the attribute. 133 | 134 | #### Returns 135 | true. 136 | 137 | #### Example 138 | `op.attributes.setOne ("age", random (1, 99))` 139 | 140 | - *true* 141 | 142 | ## op.bold 143 | #### Syntax 144 | op.bold () 145 | 146 | #### Params 147 | None. 148 | 149 | #### What it does 150 | The selected text in the bar cursor headline is boldened. 151 | 152 | #### Notes 153 | The text is boldened by wrapping it in an HTML <b> element. 154 | 155 | #### Returns 156 | undefined. 157 | 158 | #### Example 159 | `op.bold ()` 160 | 161 | - *undefined* 162 | 163 | ## op.collapseEverything 164 | #### Syntax 165 | op.collapseEverything () 166 | 167 | #### Params 168 | None. 169 | 170 | #### What it does 171 | Collapses everything in the outline and moves the bar cursor to the first summit. 172 | 173 | #### Returns 174 | The value undefined. 175 | 176 | #### Bug 177 | The bar cursor does not go to the first summit, there is no cursor after this runs. 178 | 179 | #### Example 180 | `op.collapseEverything ()` 181 | 182 | - *undefined* 183 | 184 | ## op.collapse 185 | #### Syntax 186 | op.collapse () 187 | 188 | #### Params 189 | None. 190 | 191 | #### What it does 192 | Collapses the bar cursor headline making all its children not visible. 193 | 194 | #### Returns 195 | The value undefined. 196 | 197 | #### Example 198 | `op.collapse ()` 199 | 200 | - *undefined* 201 | 202 | ## op.countSubs 203 | #### Syntax 204 | op.countSubs () 205 | 206 | #### Params 207 | None. 208 | 209 | #### Returns 210 | The number of children the bar cursor headline has. 211 | 212 | #### Example 213 | `op.countSubs ()` 214 | 215 | - *1* 216 | 217 | ## op.deleteSubs 218 | #### Syntax 219 | op.deleteSubs () 220 | 221 | #### Params 222 | None. 223 | 224 | #### What it does 225 | Deletes all the children of the bar cursor headline. 226 | 227 | #### Returns 228 | undefined. 229 | 230 | #### Examples 231 | `op.deleteSubs ()` 232 | 233 | - *undefined* 234 | 235 | ## op.demote 236 | #### Syntax 237 | op.demote () 238 | 239 | #### Params 240 | None. 241 | 242 | #### What it does 243 | All siblings down from the bar cursor headline are moved to the right, to become children of the bar cursor headline. 244 | 245 | The bar cursor headline is expanded if necessary. 246 | 247 | #### Returns 248 | undefined. 249 | 250 | #### Examples 251 | `op.demote ()` 252 | 253 | - *undefined* 254 | 255 | ## op.expandAllLevels 256 | #### Syntax 257 | op.expandAllLevels () 258 | 259 | #### Params 260 | None. 261 | 262 | #### What it does 263 | Expands the bar cursor headline making all its children, and all their descendants, visible. 264 | 265 | #### Returns 266 | The value undefined. 267 | 268 | #### Example 269 | `op.expandAllLevels ()` 270 | 271 | - *undefined* 272 | 273 | ## op.expand 274 | #### Syntax 275 | op.expand () 276 | 277 | #### Params 278 | None. 279 | 280 | #### What it does 281 | Expands the bar cursor headline making all its children visible. 282 | 283 | #### Returns 284 | The value undefined. 285 | 286 | #### Notes 287 | The Frontier version of this verb takes a number param, that determines the number of levels to be expanded. 288 | 289 | #### Example 290 | `op.expand ()` 291 | 292 | - *undefined* 293 | 294 | ## op.expandTo 295 | #### Syntax 296 | op.expandTo ( 297 | 298 | ## op.firstSummit 299 | #### Syntax 300 | op.firstSummit () 301 | 302 | #### Params 303 | None. 304 | 305 | #### Returns 306 | undefined. 307 | 308 | #### Bug 309 | It does not return undefined, it returns true. 310 | 311 | #### Example 312 | `op.firstSummit ()` 313 | 314 | - *true* 315 | 316 | ## op.getCursorJstruct 317 | #### Syntax 318 | op.getCursorJstruct () 319 | 320 | #### Params 321 | None. 322 | 323 | #### Returns 324 | A JavaScript object representing all the data in the outline subordinate to the bar cursor headline. 325 | 326 | This is useful if you want to process the text under the bar cursor headline by traversing a JavaScript object. 327 | 328 | #### Example 329 | `op.getCursorJstruct ()` 330 | 331 |
      {
       332 |     "created": "Tue, 16 Nov 2021 14:55:40 GMT",
       333 |     "text": "Hello World"
       334 |     }
       335 | 
      336 | ## op.getCursorOpml 337 | #### Syntax 338 | op.getCursorOpml (flSubsOnly) 339 | 340 | #### Params 341 | The boolean parameter is optional. If true, we return the OPML text for the subs only, otherwise we include the bar cursor headline. 342 | 343 | If it's not specified it defaults to false. 344 | 345 | #### Returns 346 | A string containing the OPML text of the bar cursor headline and all its subs, if flSubsOnly is false. If flSubsOnly is true, it returns the OPML text for the subs. 347 | 348 | #### Note 349 | The title in the <head> section of the OPML is set to the text of the bar cursor headline, so even if flSubsOnly is true, the text of the bar cursor headline is still included in the OPML. 350 | 351 | The optional boolean was added on 11/28/2021 to provide a way to get just the subs, but the default behavior was as it was before, so as not to break any existing scripts. 352 | 353 | #### Examples 354 | `op.getCursorOpml (true)` 355 | 356 | - *<?xml version="1.0"?>* 357 | 358 |
      <opml version="2.0">
       359 |     <head>
       360 |         <title>Foods I like</title>
       361 |         </head>
       362 |     <body>
       363 |         <outline text="Lettuce"/>
       364 |         <outline text="Beans">
       365 |             <outline text="String"/>
       366 |             <outline text="Baked" created="Sun, 28 Nov 2021 14:43:14 GMT"/>
       367 |             </outline>
       368 |         <outline text="Cake"/>
       369 |         </body>
       370 |     </opml>
       371 | 
      372 | `op.getCursorOpml (false)` 373 | 374 | - *<?xml version="1.0"?>* 375 | 376 |
      <opml version="2.0">
       377 |     <head>
       378 |         <title>Foods I like</title>
       379 |         </head>
       380 |     <body>
       381 |         <outline text="Foods I like" type="outline">
       382 |             <outline text="Lettuce"/>
       383 |             <outline text="Beans">
       384 |                 <outline text="String"/>
       385 |                 <outline text="Baked"/>
       386 |                 </outline>
       387 |             <outline text="Cake"/>
       388 |             </outline>
       389 |         </body>
       390 |     </opml>
       391 | 
      392 | ## op.getCursor 393 | #### Syntax 394 | op.getCursor () 395 | 396 | #### Params 397 | None. 398 | 399 | #### Bug 400 | There does not appear to be an op.setCursor to balance this verb. 401 | 402 | #### Returns 403 | An object representing the bar cursor. 404 | 405 | #### Example 406 | `op.getCursor ()` 407 | 408 | - *{ "attributes": { "_cssTextClassName": "cssTextClass" } }* 409 | 410 | ## op.getLineText 411 | #### Syntax 412 | op.getLineText () 413 | 414 | #### Params 415 | None. 416 | 417 | #### Returns 418 | The text on the bar cursor headline. 419 | 420 | #### Example 421 | `op.getLineText ()` 422 | 423 | - *But what is the protocol if the user hits Cancel?* 424 | 425 | ## op.getOutlineJstruct 426 | #### Syntax 427 | op.getOutlineJstruct () 428 | 429 | #### Params 430 | None. 431 | 432 | #### Returns 433 | A JavaScript object representing all the data in the outline. 434 | 435 | This is useful if you want to process the outline in JavaScript code in the most natural way. 436 | 437 | #### Notes 438 | Functionally, this verb does exactly what opml.getCurrentObject does, but this verb should be quite a bit faster for large outlines. 439 | 440 | It's similar to op.getCursorJstruct, which gets the outline structure underneath the bar cursor headline. 441 | 442 | #### Example 443 | `op.getOutlineJstruct ()` 444 | 445 |
      {
       446 |     "head": {
       447 |         "title": "test",
       448 |         "dateCreated": "Wed, 07 Apr 2021 16:05:20 GMT",
       449 |         "dateModified": "Wed, 07 Apr 2021 16:17:01 GMT"
       450 |         },
       451 |     "body": {
       452 |         "subs": [
       453 |             {
       454 |                 "text": "Hello World",
       455 |                 "created": "Wed, 07 Apr 2021 15:53:15 GMT"
       456 |                 }
       457 |             ]
       458 |         }
       459 |     }
       460 | 
      461 | ## op.getRenderMode 462 | #### Syntax 463 | op.getRenderMode () 464 | 465 | #### Params 466 | None. 467 | 468 | #### Returns 469 | true if the outline is in render mode, false otherwise. 470 | 471 | #### Example 472 | `op.getRenderMode ()` 473 | 474 | - *true* 475 | 476 | `op.setRenderMode (true)` 477 | 478 | - *undefined* 479 | 480 | ## op.getSelectedText 481 | #### Syntax 482 | op.getSelectedText () 483 | 484 | #### Params 485 | None. 486 | 487 | #### Returns 488 | The selected text if there is a selection, undefined if there isn't. 489 | 490 | #### See also 491 | op.replaceSelectedText () 492 | 493 | #### Example 494 | `op.getSelectedText ()` 495 | 496 | - *"Toy Story"* 497 | 498 | ## op.go 499 | #### Syntax 500 | op.go (direction, count) 501 | 502 | #### Params 503 | direction is one of the directions the outliner supports: up, down, left, right, flatup, flatdown, nodirection. 504 | 505 | count is the number of times the cursor will move in the indicated direction. 506 | 507 | #### What it does 508 | It tries to move the bar cursor in the indicated directions, the indicated number of times. 509 | 510 | - *up - bar cursor moves to previous sibling* 511 | 512 | - *down -- bar cursor moves to next sibling* 513 | 514 | - *left -- bar cursor moves to parent* 515 | 516 | - *right -- bar cursor moves to first child, expanding if necessary* 517 | 518 | - *flatup -- bar cursor moves to the previous headline up from the cursor, regardless of level* 519 | 520 | - *flatdown -- bar cursor moves to the next headline down from the cursor, regardless of level* 521 | 522 | #### Returns 523 | true if it was able to move, false otherwise. 524 | 525 | #### Examples 526 | `op.go (left, 1)` 527 | 528 | - *true* 529 | 530 | `op.go (flatdown, 1)` 531 | 532 | - *true* 533 | 534 | `op.go (down, 1)` 535 | 536 | - *false* 537 | 538 | ## op.hasSubs 539 | #### Syntax 540 | op.hasSubs () 541 | 542 | #### Params 543 | None. 544 | 545 | #### Returns 546 | True if the bar cursor headline has children, false if it doesn't. 547 | 548 | #### Example 549 | `op.hasSubs ()` 550 | 551 | - *true* 552 | 553 | ## op.insertInCalendar 554 | #### Syntax 555 | op.insertInCalendar (string, object) 556 | 557 | #### Params 558 | The string is the text of the headline that will be created. 559 | 560 | The object is a JavaScript object containing the attributes to be attached to the new headline. 561 | 562 | Both params are optional, if the string is not defined we use the empty string, if the object is not defined, we create one with a single attribute, created, containing the current date/.time. 563 | 564 | #### What it does 565 | A new headline is created in the active outline in a calendar structure of months, with days, exactly as the big plus icon does. 566 | 567 | We use the created attribute to determine where in the calendar structure to put the headline. 568 | 569 | #### Returns 570 | undefined. 571 | 572 | #### Examples 573 | `op.insertInCalendar ()` 574 | 575 | - *undefined* 576 | 577 | `op.insertInCalendar ("hello", {color: "blue", age: 22})` 578 | 579 | - *undefined* 580 | 581 | ## op.insertOpml 582 | #### Syntax 583 | op.insertOpml (opmltext, direction) 584 | 585 | #### Params 586 | opmltext is a string containing the text representing an outline to be inserted relative to the bar cursor headline. 587 | 588 | direction indicates where the new headline will go. 589 | 590 | - *up, to create a previous sibling, * 591 | 592 | - *down, to create a next sibling. * 593 | 594 | - *left to create a sibling down from its parent. * 595 | 596 | - *right to create a new first child of the bar cursor headline.* 597 | 598 | #### Returns 599 | true. 600 | 601 | #### Examples 602 | `op.insertOpml ("", down)` 603 | 604 | - *true* 605 | 606 | ## op.insert 607 | #### Syntax 608 | op.insert (string, direction) 609 | 610 | #### Params 611 | string is the text of the new headline to be created relative to the bar cursor headline. 612 | 613 | direction indicates where the new headline will go. 614 | 615 | - *up, to create a previous sibling, * 616 | 617 | - *down, to create a next sibling. * 618 | 619 | - *left to create a sibling down from its parent. * 620 | 621 | - *right to create a new first child of the bar cursor headline.* 622 | 623 | #### Returns 624 | true. 625 | 626 | #### Bug 627 | The returned value looks like some kind of jQuery object. Should be fixed! 628 | 629 | #### Example 630 | `op.insert ("North Carolina", down)` 631 | 632 | - *true* 633 | 634 | ## op.isComment 635 | #### Syntax 636 | op.isComment () 637 | 638 | #### Params 639 | None. 640 | 641 | #### Returns 642 | true if the bar cursor headline is a comment, false otherwise. 643 | 644 | #### Example 645 | `op.isComment ()` 646 | 647 | - *true* 648 | 649 | ## op.italic 650 | #### Syntax 651 | op.italic () 652 | 653 | #### Params 654 | None. 655 | 656 | #### What it does 657 | The selected text in the bar cursor headline is italicized. 658 | 659 | #### Notes 660 | The text is boldened by wrapping it in an HTML <i> element. 661 | 662 | #### Returns 663 | undefined. 664 | 665 | #### Example 666 | `op.italic ()` 667 | 668 | - *undefined* 669 | 670 | ## op.link 671 | #### Syntax 672 | op.link (string) 673 | 674 | #### Params 675 | string is a web address, a url. 676 | 677 | #### Returns 678 | undefined. 679 | 680 | #### Example 681 | `op.link ("http://scripting.com/")` 682 | 683 | - *undefined* 684 | 685 | ## op.makeComment 686 | #### Syntax 687 | op.makeComment () 688 | 689 | #### Params 690 | None. 691 | 692 | #### What it does 693 | It makes the bar cursor headline a comment. 694 | 695 | #### Returns 696 | true if the bar cursor headline is a comment, false otherwise. 697 | 698 | #### Example 699 | `op.makeComment ()` 700 | 701 | - *true* 702 | 703 | ## op.promote 704 | #### Syntax 705 | op.promote () 706 | 707 | #### Params 708 | None. 709 | 710 | #### What it does 711 | If the bar cursor headline has children, they are all moved to the left, to become siblings of the bar cursor headline. 712 | 713 | #### Returns 714 | undefined. 715 | 716 | #### Examples 717 | `op.promote ()` 718 | 719 | - *undefined* 720 | 721 | ## op.reorg 722 | #### Syntax 723 | op.reorg (direction, count) 724 | 725 | #### Params 726 | direction is one of the directions the outliner supports: up, down, left, right, flatup, flatdown, nodirection. 727 | 728 | count is the number of times the bar cursor outline will move in the indicated direction. 729 | 730 | #### What it does 731 | It reorganizes the outline. The operation is performed on the sub-outline the bar cursor points to and one of its adjacent siblings or parent. 732 | 733 | If direction is down, the bar cursor headline and all its descendants, switches places with its next sibling. If it's already the last sibling, it doesn't move. 734 | 735 | If the direction is up, the bar cursor outline switches places with its previous sibling. 736 | 737 | If the direction is right, it becomes the last child of its previous sibling. If it's already the first sibling, it doesn't move. 738 | 739 | If the direction is left, it becomes the next sibling of its parent. If it's already at the top level of the outline (it's a summit), it doesn't move. 740 | 741 | #### Returns 742 | true if it was able to move, false otherwise. 743 | 744 | #### Examples 745 | `op.reorg (left, 1)` 746 | 747 | - *true* 748 | 749 | `op.go (left, infinity)` 750 | 751 | - *true* 752 | 753 | ## op.replaceSelectedText 754 | #### Syntax 755 | op.replaceSelectedText (string) 756 | 757 | #### What it does 758 | Replaces the selected text with the string param. 759 | 760 | #### Params 761 | The string is the text to replace the selected text with. 762 | 763 | #### Returns 764 | If there is a selection, it returns the text we replaced the selection with. If there is no selection, it returns undefined. 765 | 766 | #### Notes 767 | To delete the selected text, replace it with the empty string. 768 | 769 | #### See also 770 | op.getSelectedText () 771 | 772 | #### Example 773 | `op.replaceSelectedText ("Finding Nemo")` 774 | 775 | - *"Toy Story"* 776 | 777 | `op.replaceSelectedText (string.upper (op.getSelectedText ()))` 778 | 779 | - *"TOY STORY"* 780 | 781 | ## op.runSelection 782 | #### Syntax 783 | op.runSelection () 784 | 785 | #### Params 786 | None. 787 | 788 | #### Returns 789 | undefined. 790 | 791 | #### Bug 792 | It uses the old form of running the selection. 793 | 794 | #### Example 795 | `op.runSelection ()` 796 | 797 | ## op.setCursor 798 | #### Syntax 799 | op.setCursor (object) 800 | 801 | #### Params 802 | The object is the result of an op.getCursor call. 803 | 804 | #### Returns 805 | An object representing the bar cursor. 806 | 807 | #### Example 808 | `op.setCursor (origCursor)` 809 | 810 | - *{ "attributes": { "_cssTextClassName": "cssTextClass" } }* 811 | 812 | ## op.setLineText 813 | #### Syntax 814 | op.setLineText (string) 815 | 816 | #### Params 817 | The string is the text that will replace the text of the bar cursor headline. 818 | 819 | #### Returns 820 | true. 821 | 822 | #### Example 823 | `op.setLineText ("Hi mom!")` 824 | 825 | - *true* 826 | 827 | ## op.setRenderMode 828 | #### Syntax 829 | op.setRenderMode (boolean) 830 | 831 | #### Params 832 | boolean determines whether we go into or out of render mode. 833 | 834 | #### What it does 835 | In render mode the outline is displayed with HTML rendered. The markup is not visible. So for example, bold text appears bold, not within a <b> tag. 836 | 837 | #### Returns 838 | true if the bar cursor headline is a comment, false otherwise. 839 | 840 | #### Examples 841 | `op.setRenderMode (false)` 842 | 843 | - *undefined* 844 | 845 | `op.setRenderMode (true)` 846 | 847 | - *undefined* 848 | 849 | ## op.setTextMode 850 | #### Syntax 851 | op.setTextMode (boolean) 852 | 853 | #### Params 854 | The boolean indicates whether we should switch into text mode (true) or out of text mode (false). 855 | 856 | #### Notes 857 | When the outliner is in text mode, the bar cursor is not visible. 858 | 859 | Instead there's a flashing vertical line that indicates the cursor's position. When you type, text is inserted at that point. Going into text mode is an indicator to the user that they can enter text. 860 | 861 | You can enter text when you're not in text mode, but in that case, any typing replaces the text in the bar cursor headline. 862 | 863 | #### Returns 864 | undefined. 865 | 866 | #### Example 867 | `op.setTextMode (true)` 868 | 869 | - *undefined* 870 | 871 | ## op.strikethrough 872 | #### Syntax 873 | op.strikethrough () 874 | 875 | #### Params 876 | None. 877 | 878 | #### What it does 879 | The selected text in the bar cursor headline is italicized. 880 | 881 | #### Notes 882 | The text is boldened by wrapping it in an HTML <i> element. 883 | 884 | #### Returns 885 | undefined. 886 | 887 | #### Example 888 | `op.strikethrough ()` 889 | 890 | - *undefined* 891 | 892 | ## op.toggleComment 893 | #### Syntax 894 | op.toggleComment () 895 | 896 | #### Params 897 | None. 898 | 899 | #### What it does 900 | If the bar cursor headline is not a comment it makes it one, and if it is a comment, it makes it not a comment. 901 | 902 | #### Returns 903 | undefined. 904 | 905 | #### Example 906 | `op.toggleComment ()` 907 | 908 | - *undefined* 909 | 910 | ## op.toggleRenderMode 911 | #### Syntax 912 | op.toggleRenderMode () 913 | 914 | #### Params 915 | None. 916 | 917 | #### What it does 918 | If you're in render mode, after this verb runs your outline will no longer be in render mode, and if you're not in render mode, after running this verb your outline will no longer be in render mode. 919 | 920 | #### Returns 921 | undefined. 922 | 923 | #### Example 924 | `op.toggleRenderMode ()` 925 | 926 | - *undefined* 927 | 928 | ## op.visitAll 929 | #### Syntax 930 | op.visitAll (callback) 931 | 932 | #### Params 933 | The callback is a function that is called for every headline in the outline, in order, from top to bottom, regardless of whether the headlines are expanded. 934 | 935 | #### Returns 936 | undefined. 937 | 938 | #### Notes 939 | The example below is provided in the Scripts menu demo outline, under Outlines. 940 | 941 | There's a separate docs page on the op visit verbs. We will provide a link to that page here. 942 | 943 | #### See also 944 | There's a separate docs page on the op visit verbs. We will provide a link to that page here. 945 | 946 | #### Example 947 | `op.visitAll (function (headline) {` 948 | 949 | - *console.log (headline.getLineText ());* 950 | 951 | - *return (true);* 952 | 953 | - *});* 954 | 955 | ## op.visitSubs 956 | #### Syntax 957 | op.visitSubs (callback) 958 | 959 | #### Params 960 | The callback is a function that is called for every headline subordinate to the bar cursor headline, whether or not they're expanded, in order from top to bottom, depth-first. 961 | 962 | #### Returns 963 | undefined. 964 | 965 | #### Notes 966 | The example below is provided in the Scripts menu demo outline, under Outlines. 967 | 968 | There's a separate docs page on the op visit verbs. We will provide a link to that page here. 969 | 970 | The callback for op.visitSubs receives a second parameter, a number, the level of the headline being visited, relative to the bar cursor headline. The level is zero-based, meaning the immediate subs of the BCH are level 0, their subs are level 1, etc. 971 | 972 | #### Example 973 | `op.visitSubs (function (headline, level) {` 974 | 975 | - *console.log (string.filledString ("\t", level) + headline.getLineText ());* 976 | 977 | - *return (true);* 978 | 979 | - *});* 980 | 981 | ## op.visitToSummit 982 | #### Syntax 983 | op.visitToSummit (callback) 984 | 985 | #### Params 986 | The callback is a function that is called for every headline on the path from the bar cursor headline to the summit of the outline. 987 | 988 | #### Returns 989 | undefined. 990 | 991 | #### Notes 992 | The example below is provided in the Scripts menu demo outline, under Outlines. 993 | 994 | There's a separate docs page on the op visit verbs. We will provide a link to that page here. 995 | 996 | #### Example 997 | `op.visitToSummit (function (headline) {` 998 | 999 | - *console.log (headline.getLineText ());* 1000 | 1001 | - *return (true);* 1002 | 1003 | - *});* 1004 | 1005 | -------------------------------------------------------------------------------- /docs/pages/string.md: -------------------------------------------------------------------------------- 1 | 2 | # string verbs 3 | ## string.addCommas 4 | #### Syntax 5 | string.addCommas (number) 6 | 7 | #### Params 8 | The param is a large number that can be made easier to read by adding commas to it. 9 | 10 | #### Returns 11 | A string. 12 | 13 | #### Examples 14 | `string.addCommas (11709445200)` 15 | 16 | - *11,709,445,200* 17 | 18 | `string.addCommas (12)` 19 | 20 | - *12* 21 | 22 | `string.addCommas ("abcdefghijklmnopqrstuvwxyz")` 23 | 24 | - *abcdefghijklmnopqrstuvwxyz* 25 | 26 | ## string.addPeriodAtEnd 27 | #### Syntax 28 | string.addPeriodAtEnd (string) 29 | 30 | #### Params 31 | string is a sentence that may not have a period at the end. 32 | 33 | #### Returns 34 | The string, possibly with a period added at the end. 35 | 36 | #### Notes 37 | It's a complicated and somewhat quirky algorithm. 38 | 39 | First we call string.trimWhitespace to remove any spaces or newlines at the beginning and end of the string. 40 | 41 | Then, if the string ends with a period, comma, question mark, quote, colon, semicolon or exclamation point, we do nothing. Putting a period after these characters would usually be incorrect. 42 | 43 | Used in Radio3 to pre-process a linkblog post. 44 | 45 | #### Examples 46 | `string.addPeriodAtEnd ("I like ice cream")` 47 | 48 | - *I like ice cream.* 49 | 50 | `string.addPeriodAtEnd ("What is your favorite flavor?")` 51 | 52 | - *What is your favorite flavor?* 53 | 54 | ## string.beginsWith 55 | #### Syntax 56 | string.beginsWith (s, possibleBeginning, flUnicase) 57 | 58 | #### Params 59 | The first param is a string that might begin with the second param. 60 | 61 | flUnicase, a boolean, is optional. If true the search is done regardless of the case of the characters. If true the match doesn't have to be exact regarding the case of the characters, so "hooray" will match "Hooray" or "hOOrAy" if flUnicase is true. 62 | 63 | #### Returns 64 | true if the string begins with the other, false if it doesn't. 65 | 66 | #### Example 67 | `string.beginsWith ("hooray for hollywood", "hoo")` 68 | 69 | - *true* 70 | 71 | ## string.bumpUrlString 72 | #### Syntax 73 | string.bumpUrlString (string) 74 | 75 | #### Params 76 | string either undefined or the result of having called string.bumpUrlString. 77 | 78 | #### Returns 79 | The next string in the sequence, as in a URL shortener application. 80 | 81 | #### Notes 82 | The first string it returns is 1, then 2, then it runs through the alphabet. After z it returns 00, then 01. 83 | 84 | It can be used in implementing a URL shortener, to generate a sequence of strings, that can be used as aliases for another perhaps longer string. 85 | 86 | #### Examples 87 | `string.bumpUrlString (undefined)` 88 | 89 | - *1* 90 | 91 | `string.bumpUrlString ("z")` 92 | 93 | - *00* 94 | 95 | `string.bumpUrlString ("zz")` 96 | 97 | - *000* 98 | 99 | `string.bumpUrlString ("ZZ") //not case-sensitive` 100 | 101 | - *000* 102 | 103 | ## string.contains 104 | #### Syntax 105 | string.contains (s, whatItMightContain, flUnicase) returns boolean 106 | 107 | #### What it does 108 | Determines if one string contains another. 109 | 110 | The third parameter, flUnicase, is optional, it defaults to true. 111 | 112 | #### Returns 113 | true if the string contains the other, false if it doesn't. 114 | 115 | #### Example 116 | `dialog.alert (string.contains ("http://november.com", "november")) //displays true` 117 | 118 | ## string.countFields 119 | #### Syntax 120 | string.countFields (s, ch) 121 | 122 | #### Params 123 | s is a string, ch is a 1-character string. 124 | 125 | #### Returns 126 | The number of fields in the string, with fields determined by the character. 127 | 128 | #### Examples 129 | `string.countFields ("scripting.com/2003/08/12.html", "/")` 130 | 131 | - *4* 132 | 133 | `string.countFields ("Do you know the way to San Jose?", " ")` 134 | 135 | - *8* 136 | 137 | `string.countFields ("Come hear Uncle John's Band.", "/")` 138 | 139 | - *1* 140 | 141 | #### See also 142 | string.nthField 143 | 144 | string.lastField 145 | 146 | ## string.dayOfWeekToString 147 | #### Syntax 148 | string.dayOfWeekToString (number) 149 | 150 | #### Param 151 | A number between 0 and 6. 0 corresponds to Sunday, 6 to Saturday. 152 | 153 | #### Returns 154 | A string like "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" or the empty string. 155 | 156 | #### Errors 157 | If the number is out of range it returns the empty string. 158 | 159 | #### Example 160 | `string.dayOfWeekToString (3)` 161 | 162 | - *Wednesday* 163 | 164 | #### See also 165 | string.monthToString 166 | 167 | ## string.decodeXml 168 | #### Syntax 169 | string.decodeXml (string) 170 | 171 | #### Params 172 | A string that may include encoded XML. 173 | 174 | #### Returns 175 | The decoded version of the string. 176 | 177 | #### Notes 178 | We look for four strings: &lt; &gt; &amp; and &apos; and convert them to < > & and '. 179 | 180 | At some point it may make sense to look for other strings. 181 | 182 | #### Examples 183 | `string.decodeXml ("&lt;script&gt;")` 184 | 185 | - *<script>* 186 | 187 | `string.decodeXml ("Lennon &amp; McCartney")` 188 | 189 | - *Lennon & McCartney* 190 | 191 | ## string.delete 192 | #### Syntax 193 | string.delete (string, index, count) 194 | 195 | #### Params 196 | The first parameter is a string that you want to delete characters from. 197 | 198 | The second parameter is the 1-based location of the first character to delete. 199 | 200 | The third parameter is the number of characters to delete. 201 | 202 | #### Returns 203 | The result of deleting the characters from the string. 204 | 205 | #### Notes 206 | If you try to delete more characters than are present, it deletes as many as it can. 207 | 208 | If you try to delete starting past the end of the string, you end up deleting nothing. 209 | 210 | #### Example 211 | `string.delete ("123456789", 3, 1)` 212 | 213 | - *12456789* 214 | 215 | `string.delete ("123456789", 2, 1000)` 216 | 217 | - *1* 218 | 219 | `string.delete ("123456789", 100, 3)` 220 | 221 | - *123456789* 222 | 223 | ## string.encodeHtml 224 | #### Syntax 225 | string.encodeHtml (string) 226 | 227 | #### Params 228 | A string that possibly contains HTML markup. 229 | 230 | #### Returns 231 | The result of encoding angle brackets and quotes. 232 | 233 | #### Notes 234 | If you try to delete more characters than are present, it deletes as many as it can. 235 | 236 | If you try to delete starting past the end of the string, you end up deleting nothing. 237 | 238 | #### Examples 239 | `string.encodeHtml ("Still diggin!")` 240 | 241 | - *Still diggin!* 242 | 243 | `string.encodeHtml ("I love a parade")` 244 | 245 | - *I <b>love</b> a parade* 246 | 247 | ## string.endsWith 248 | #### Syntax 249 | string.endsWith (string1, string2, boolean) 250 | 251 | #### Params 252 | The first string is the one we're looking in. 253 | 254 | The second is what we're looking for in the string. 255 | 256 | The boolean says if the search is unicase (it's optional, if not present it's true). 257 | 258 | #### Returns 259 | True if the first string ends with the second. 260 | 261 | #### Examples 262 | `string.endsWith ("Hooray for Hollywood", "wood")` 263 | 264 | - *true* 265 | 266 | `string.endsWith ("Hooray for Hollywood", "Wood", false)` 267 | 268 | - *false* 269 | 270 | `string.endsWith ("Hooray for Hollywood", "wheat")` 271 | 272 | - *false* 273 | 274 | ## string.extensionToMimeType 275 | #### Syntax 276 | string.extensionToMimeType (string) 277 | 278 | #### Params 279 | The string is a path to a file. 280 | 281 | #### Returns 282 | Returns a media type corresponding to the extension of the file. 283 | 284 | For example, if the extension is .html, it returns text/html. 285 | 286 | If there is no extension or the extension isn't recognized, it returns undefined. 287 | 288 | #### Note 289 | string.extensionToMimeType calls the daveutils function httpExt2MIME. 290 | 291 | #### Examples 292 | `string.extensionToMimeType ("ideas.html")` 293 | 294 | - *text/html* 295 | 296 | `string.extensionToMimeType ("config.json")` 297 | 298 | - *application/json* 299 | 300 | `string.extensionToMimeType ("config.js")` 301 | 302 | - *application/javascript* 303 | 304 | `string.extensionToMimeType ("profile.png")` 305 | 306 | - *image/png* 307 | 308 | `string.extensionToMimeType ("profile.jpg")` 309 | 310 | - *image/jpeg* 311 | 312 | ## string.filledString 313 | #### Syntax 314 | string.filledString (character, count) 315 | 316 | #### Params 317 | The first parameter is a string which will be replicated. 318 | 319 | The second parameter is the number of times it will be replicated. 320 | 321 | #### Returns 322 | A string containing a number of copies of the first parameter. 323 | 324 | #### Examples 325 | `string.filledString ("p", 10)` 326 | 327 | - *pppppppppp* 328 | 329 | `string.filledString ("123 ", 10)` 330 | 331 | - *123 123 123 123 123 123 123 123 123 123 * 332 | 333 | `string.filledString ("\t", 3)` 334 | 335 | - * * 336 | 337 | ## string.formatDate 338 | #### Syntax 339 | string.formatDate (date, format, timezone) 340 | 341 | #### Params 342 | The first parameter is a JavaScript date object. 343 | 344 | The second parameter is a string containing a format spec, following strftime standard. 345 | 346 | The third parameter says what timezone you want the date to be in. 0 is GMT, -4 in US/Eastern. 347 | 348 | #### Returns 349 | A string, representing the date, in the format specified, in the indicated timezone. 350 | 351 | #### Notes 352 | All three parameters are optional. 353 | 354 | If the date is not specified, the current date-time is used. 355 | 356 | If the format is not specified, we use "%c". 357 | 358 | If the timezone is not specified, we use the timezone that the machine that ran the script is in. 359 | 360 | #### Examples 361 | `string.formatDate (clock.now (), "%B")` 362 | 363 | - *March* 364 | 365 | `string.formatDate ()` 366 | 367 | - *Sun Mar 14 2021 11:24:53 GMT-0400 (Eastern Daylight Time)* 368 | 369 | `string.formatDate (clock.now (), "%l:%M %p")` 370 | 371 | - *11:21 AM* 372 | 373 | `string.formatDate (undefined, "%A, %B %e, %Y at %l:%M %p") + "."` 374 | 375 | - *Sunday, March 14, 2021 at 11:27 AM.* 376 | 377 | ## string.getRandomPassword 378 | #### Syntax 379 | string.getRandomPassword (count) 380 | 381 | #### Params 382 | count is the number of characters that will be in the random string that's generated. 383 | 384 | #### Returns 385 | A string of random characters. 386 | 387 | #### Examples 388 | `string.getRandomPassword (20)` 389 | 390 | - *26mxjiulbv2br8jaeutj* 391 | 392 | `string.getRandomPassword (20)` 393 | 394 | - *pv8snpjvmbl4np4kh4mt* 395 | 396 | ## string.hashMD5 397 | #### Syntax 398 | string.hashMD5 (string) 399 | 400 | #### Params 401 | The string is the input to the MD5 encryption algorithm. 402 | 403 | #### Returns 404 | The encrypted version of the string. 405 | 406 | #### Notes 407 | You can tell with a lot of confidence that the sender who uses this function has a copy of the string without transmitting it. 408 | 409 | #### Examples 410 | `string.hashMD5 ("Spring forward, fall back.")` 411 | 412 | - *26d37b732af2a3caf47a0b2c9789a0ce* 413 | 414 | `string.hashMD5 ("It's even worse than it appears")` 415 | 416 | - *d7adfe509535ad6de49a8baf0fbf7a3d* 417 | 418 | ## string.innerCaseName 419 | #### Syntax 420 | string.innerCaseName (string) 421 | 422 | #### Params 423 | A string that contains words separated by spaces. 424 | 425 | #### Returns 426 | The innerCase version of the string, which means capitalize the first letter after every space, then remove the spaces. 427 | 428 | #### Notes 429 | It's useful for creating a file name or URL from a title. 430 | 431 | #### Examples 432 | `string.innerCaseName ("The story of my life") + ".mp3"` 433 | 434 | - *theStoryOfMyLife.mp3* 435 | 436 | ## string.insert 437 | #### Syntax 438 | string.insert (source, dest, ix) 439 | 440 | #### Params 441 | source is a string that will be inserted into dest, also a string, and the 1-based index ix. 442 | 443 | #### Returns 444 | The result of the insertion. 445 | 446 | #### Bugs 447 | Behavior is unpredictable if ix is less than zero. 448 | 449 | #### Examples 450 | `string.insert ("Bull ", "My name is Mancuso.", 11)` 451 | 452 | - *My name is Bull Mancuso.* 453 | 454 | `string.insert ("Hello ", " from Hollywood", 1)` 455 | 456 | - * Hello from Hollywood* 457 | 458 | ## string.isAlpha 459 | #### Syntax 460 | string.isAlpha (ch) 461 | 462 | #### Params 463 | ch is a 1-character string. 464 | 465 | #### Returns 466 | True if it's an alphabetic character, false otherwise. 467 | 468 | Alphabetic characters are A-Z and a-z. 469 | 470 | #### Notes 471 | If the string is longer than one character, it returns true if the first character is alphabetic, false otherwise. 472 | 473 | #### Examples 474 | `string.isAlpha ("x")` 475 | 476 | - *true* 477 | 478 | `string.isAlpha ("1")` 479 | 480 | - *false* 481 | 482 | `string.isAlpha ("#")` 483 | 484 | - *false* 485 | 486 | `string.isAlpha ("123abc")` 487 | 488 | - *false* 489 | 490 | #### See also 491 | string.isNumeric 492 | 493 | string.isWhitespace 494 | 495 | string.isPunctuation 496 | 497 | ## string.isNumeric 498 | #### Syntax 499 | string.isNumeric (ch) 500 | 501 | #### Params 502 | ch is a 1-character string. 503 | 504 | #### Returns 505 | True if it's a numeric character, false otherwise. 506 | 507 | Numeric characters are 0-9. 508 | 509 | #### Notes 510 | If the string is longer than one character, it returns true if the first character is numeric, false otherwise. 511 | 512 | #### Examples 513 | `string.isNumeric ("4")` 514 | 515 | - *true* 516 | 517 | `string.isNumeric ("g")` 518 | 519 | - *false* 520 | 521 | `string.isNumeric ("#")` 522 | 523 | - *false* 524 | 525 | `string.isNumeric ("123abc")` 526 | 527 | - *true* 528 | 529 | #### See also 530 | string.isAlpha 531 | 532 | string.isWhitespace 533 | 534 | string.isPunctuation 535 | 536 | ## string.isPunctuation 537 | #### Syntax 538 | string.isPunctuation (ch) 539 | 540 | #### Params 541 | ch is a 1-character string. 542 | 543 | #### Returns 544 | True if it's a punctuation character, false otherwise. 545 | 546 | Punctuation characters all characters that are not alpha, numeric or whitespace characters. 547 | 548 | #### Notes 549 | If the string is longer than one character, it returns true if the first character is numeric, false otherwise. 550 | 551 | This function can in some cases be used to see if you need to add a period at the end of a sentence. 552 | 553 | #### Bugs 554 | Admittedly, its definition is weird, it would probably be better to enumerate the characters that are punctuation, for example, period, comma, colon, semicolon. 555 | 556 | #### Examples 557 | `string.isPunctuation (" ")` 558 | 559 | - *false* 560 | 561 | `string.isPunctuation (".")` 562 | 563 | - *true* 564 | 565 | `string.isPunctuation (",")` 566 | 567 | - *true* 568 | 569 | #### See also 570 | string.isAlpha 571 | 572 | string.isWhitespace 573 | 574 | string.isNumeric 575 | 576 | string.isPunctuation 577 | 578 | string.trimWhitespace 579 | 580 | ## string.isWhitespace 581 | #### Syntax 582 | string.isWhitespace (ch) 583 | 584 | #### Params 585 | ch is a 1-character string. 586 | 587 | #### Returns 588 | True if it's a whitespace character, false otherwise. 589 | 590 | Whitespace characters are " ", "\r", "\n", "\t" (i.e. blank, return, newline and tab). 591 | 592 | #### Notes 593 | If the string is longer than one character, it returns true if the first character is numeric, false otherwise. 594 | 595 | #### Examples 596 | `string.isWhitespace (" ")` 597 | 598 | - *true* 599 | 600 | `string.isWhitespace ("\n")` 601 | 602 | - *true* 603 | 604 | `string.isWhitespace ("*")` 605 | 606 | - *false* 607 | 608 | #### See also 609 | string.isAlpha 610 | 611 | string.isWhitespace 612 | 613 | string.isNumeric 614 | 615 | string.isPunctuation 616 | 617 | string.trimWhitespace 618 | 619 | ## string.lastField 620 | #### Syntax 621 | string.lastField (s, ch) 622 | 623 | #### Params 624 | s is a string, ch is a 1-character string. 625 | 626 | #### Returns 627 | A string with the contents of the last specified field in the string, with fields determined by the character. 628 | 629 | If ch doesn't appear in the string, it returns the whole string. 630 | 631 | #### Bugs 632 | If ch contains more than one character, the results are not easily specified. 633 | 634 | #### Examples 635 | `string.lastField ("scripting.com/2003/08/12.html", "/")` 636 | 637 | - *12.html* 638 | 639 | `string.lastField ("oh the buzzing of the bees", " ")` 640 | 641 | - *bees* 642 | 643 | `string.lastField ("oh the buzzing of the bees", "123")` 644 | 645 | - *oh the buzzing of the bees* 646 | 647 | #### See also 648 | string.nthField 649 | 650 | string.countFields 651 | 652 | ## string.lower 653 | #### Syntax 654 | string.lower (s) returns string 655 | 656 | #### What it does 657 | Converts the string to lower case. 658 | 659 | #### Returns 660 | The lower case version of the string. 661 | 662 | #### Example 663 | `dialog.alert (string.lower ("Everyone Do The Hamster Dance!"))` 664 | 665 | #### See also 666 | string.upper 667 | 668 | ## string.maxStringLength 669 | #### Syntax 670 | string.maxStringLength (string, maxlength, flWholeWordAtEnd, flAddElipses) 671 | 672 | #### Params 673 | The first parameter is a string that you want to be sure isn't longer than the number in the second parameter. 674 | 675 | flWholeWordAtEnd is an optional boolean param. If true, we don't leave a broken word at the end of the string. Defaults to true. 676 | 677 | flAddElipses is an optional boolean. If true, we add three periods at the end of the string. Defaults to true. 678 | 679 | #### Returns 680 | A string that is not longer than the indicated length. 681 | 682 | #### Examples 683 | `string.maxStringLength ("I have a long story I would like to tell you. It begins like this.", 35)` 684 | 685 | - *I have a long story I would like ...* 686 | 687 | `string.maxStringLength ("You know nothing Jon Snow." , 80)` 688 | 689 | - *You know nothing Jon Snow.* 690 | 691 | ## string.markdownProcess 692 | #### Syntax 693 | string.markdownProcess (string) 694 | 695 | #### Params 696 | The string contains markdown text that you want to be converted to HTML. 697 | 698 | #### Returns 699 | The HTML rendering of the string. 700 | 701 | #### Notes 702 | We use Pagedown, the Markdown processor used on Stack Exchange. 703 | 704 | #### Examples 705 | `string.markdownProcess ("It's **even** worse than it appears.")` 706 | 707 | - *

      It's even worse than it appears.

      * 708 | 709 | `string.markdownProcess ("I read [Scripting News](http://scripting.com/).")` 710 | 711 | - *

      I read Scripting News.

      * 712 | 713 | `string.markdownProcess ("* one\n* two\n* three\n")` 714 | 715 |
        716 |
      • one
      • 717 |
      • two
      • 718 |
      • three
      • 719 |
      720 |
      721 | ## string.mid 722 | #### Syntax 723 | string.mid (string, ix, ct) 724 | 725 | #### Params 726 | The first parameter is a string that you want to get characters from. 727 | 728 | The second parameter is the 1-based location of the first character to copy. 729 | 730 | The third parameter is the number of characters to copy. 731 | 732 | #### Returns 733 | The result of extracting the characters from the string. 734 | 735 | #### Notes 736 | If you try to delete copy characters than are present, it copies as many as it can. 737 | 738 | If you try to copy starting past the end of the string, you end up copying nothing. 739 | 740 | #### Example 741 | `string.mid ("123456789", 3, 1)` 742 | 743 | - *3* 744 | 745 | `string.mid ("123456789", 2, 1000)` 746 | 747 | - *23456789* 748 | 749 | #### See also 750 | string.delete 751 | 752 | string.insert 753 | 754 | ## string.monthToString 755 | #### Syntax 756 | string.monthToString (number) 757 | 758 | #### Param 759 | A number between 0 and 11. 0 corresponds to January, 11 to December. 760 | 761 | #### Returns 762 | A string like "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" or undefined. 763 | 764 | #### Examples 765 | `string.monthToString (0)` 766 | 767 | - *January* 768 | 769 | `string.monthToString (100)` 770 | 771 | - *undefined* 772 | 773 | #### See also 774 | string.dayOfWeekToString 775 | 776 | ## string.multipleReplaceAll 777 | #### Syntax 778 | string.multipleReplaceAll (s, replaceTable, flCaseSensitive, startCharacters, endCharacters) 779 | 780 | #### Params 781 | s is a string. 782 | 783 | replaceTable is an object, where the name of each property is a string to search for, and its value is what you want it replaced with. 784 | 785 | flCaseSensitive, a boolean, determines if the search is case-sensitive. It's optional, if undefined, it defaults to false. 786 | 787 | startCharacters is an optional string, if specified we only look at text within the first string that begins with these characters. 788 | 789 | endCharacters, also optional, if specified, we only look at text within the first string that ends with these characters. 790 | 791 | #### Returns 792 | A string, the result of the replacements. 793 | 794 | #### Example 795 | `string.multipleReplaceAll ("This house costs $293,000.", {"house": "apartment", "293,000": "534,287"}) ` 796 | 797 | - *This apartment costs $534,287.* 798 | 799 | #### See also 800 | string.replaceAll 801 | 802 | ## string.nthField 803 | #### Syntax 804 | string.nthField (s, ch, n) 805 | 806 | #### Params 807 | s is a string, ch is a 1-character string, n is a number. 808 | 809 | n is 1-based, i.e. the first field is 1, not 0. 810 | 811 | #### Returns 812 | A string with the contents of the specified field, with fields determined by the character. 813 | 814 | #### Example 815 | `string.nthField ("scripting.com/2003/08/12.html", "/", 3)` 816 | 817 | - *08* 818 | 819 | #### See also 820 | string.lastField 821 | 822 | string.countFields 823 | 824 | ## string.padWithZeros 825 | #### Syntax 826 | string.padWithZeros (number, ct) 827 | 828 | #### Params 829 | number is a number you want padded with zeros. 830 | 831 | ct is the number of places you want the number padded to. 832 | 833 | #### Returns 834 | The padded version of the number as a string. 835 | 836 | #### Notes 837 | It's useful if you want all strings produced by the code to be the same length, regardless how large the numbers are. 838 | 839 | #### Examples 840 | `string.padWithZeros (1200, 5)` 841 | 842 | - *01200* 843 | 844 | `string.padWithZeros (1, 4) + ".html"` 845 | 846 | - *0001.html* 847 | 848 | #### See also 849 | string.delete 850 | 851 | string.insert 852 | 853 | ## string.popExtension 854 | #### Syntax 855 | string.popExtension (s) 856 | 857 | #### Params 858 | s is a string. 859 | 860 | #### Returns 861 | If the string has an extension, like .txt or .png, we return the string without the extension. 862 | 863 | #### Example 864 | `string.popExtension ("myAffadavit.txt")` 865 | 866 | - *myAffadavit* 867 | 868 | #### See also 869 | string.popLastField 870 | 871 | string.popTrailing 872 | 873 | ## string.popLastField 874 | #### Syntax 875 | string.popLastField (s, ch) 876 | 877 | #### Params 878 | s is a string, ch is a 1-character string. 879 | 880 | #### Returns 881 | A string without the last field, as determined by the character, used as a delimiter. 882 | 883 | #### Notes 884 | Useful if you want to replace the suffix of a file name with another suffix. 885 | 886 | #### Examples 887 | `string.popLastField ("myDiary.html", ".") + ".json"` 888 | 889 | - *myDiary.json* 890 | 891 | `string.popLastField ("scripting.com/2021/03/13", "/")` 892 | 893 | - *scripting.com/2021/03* 894 | 895 | #### See also 896 | string.nthField 897 | 898 | string.countFields 899 | 900 | string.lastField 901 | 902 | ## string.popTrailing 903 | #### Syntax 904 | string.popTrailing (s, ch) 905 | 906 | #### Params 907 | s is a string, ch is a 1-character string. 908 | 909 | #### Returns 910 | A string without instances of the character at the end of the string 911 | 912 | #### Example 913 | `string.popTrailing ("get rid of the dots please.........", ".")` 914 | 915 | - *get rid of the dots please* 916 | 917 | #### See also 918 | string.popLastField 919 | 920 | string.popExtension 921 | 922 | ## string.randomSnarkySlogan 923 | #### Syntax 924 | string.randomSnarkySlogan () 925 | 926 | #### Params 927 | None. 928 | 929 | #### Returns 930 | A slogan from Dave's collection. 931 | 932 | #### Notes 933 | This is mostly for fun. Truthfully it's only for fun. Heh. ;-) 934 | 935 | #### Examples 936 | `string.randomSnarkySlogan ()` 937 | 938 | - *People return to places that send them away.* 939 | 940 | `string.randomSnarkySlogan ()` 941 | 942 | - *This aggression will not stand.* 943 | 944 | `string.randomSnarkySlogan ()` 945 | 946 | - *All of this has happened before and all of this will happen again.* 947 | 948 | `string.randomSnarkySlogan ()` 949 | 950 | - *It's even worse than it appears.* 951 | 952 | ## string.replaceAll 953 | #### Syntax 954 | string.replaceAll (s, searchFor, replaceWith) 955 | 956 | #### Params 957 | All three parameters are strings. 958 | 959 | #### Returns 960 | The result of replacing all occurrences of the second string with the third, in the first. 961 | 962 | #### Example 963 | `string.replaceAll ("raise your hand if you're happy", " ", "---")` 964 | 965 | - *raise---your---hand---if---you're---happy* 966 | 967 | #### See also 968 | string.multipleReplaceAll 969 | 970 | ## string.stripMarkup 971 | #### Syntax 972 | string.stripMarkup (string) 973 | 974 | #### Params 975 | A string that might contain HTML markup. 976 | 977 | #### Returns 978 | The string without the HTML markup. 979 | 980 | #### Example 981 | `string.stripMarkup ("Sometimes you don't want the markup.")` 982 | 983 | - *Sometimes you don't want the markup.* 984 | 985 | ## string.trimLeading 986 | #### Syntax 987 | string.trimLeading (string, ch) 988 | 989 | #### Params 990 | First parameter is a string, the second parameter is a 1-character string. 991 | 992 | #### Returns 993 | The string without instances of the character at the beginning of the string. 994 | 995 | #### Example 996 | `string.trimLeading ("$$$$$We don't need the dollar signs at the beginning of this string.", "$")` 997 | 998 | - *We don't need the dollar signs at the beginning of this string.* 999 | 1000 | #### See also 1001 | string.trimTrailing 1002 | 1003 | ## string.trimTrailing 1004 | #### Syntax 1005 | string.trimTrailing (string, ch) 1006 | 1007 | #### Params 1008 | First parameter is a string, the second parameter is a 1-character string. 1009 | 1010 | #### Returns 1011 | The string without instances of the character at the end of the string. 1012 | 1013 | #### Example 1014 | `string.trimTrailing ("We don't need the question marks at the end of this string.?????", "?")` 1015 | 1016 | - *We don't need the question marks at the end of this string.* 1017 | 1018 | #### See also 1019 | string.trimLeading 1020 | 1021 | ## string.trimWhitespace 1022 | #### Syntax 1023 | string.trimWhitespace (string) 1024 | 1025 | #### Params 1026 | A string that might have whitespace at the beginning and/or end. 1027 | 1028 | #### Returns 1029 | The string without whitespace characters at the beginning and end. 1030 | 1031 | #### Notes 1032 | Use this verb to allow comparisons between names or identifiers that might have whitespace around them. 1033 | 1034 | #### Example 1035 | `string.trimWhitespace (" All the whitespace is a problem. ")` 1036 | 1037 | - *All the whitespace is a problem.* 1038 | 1039 | `string.trimWhitespace (" Alice ") == "Alice"` 1040 | 1041 | - *true* 1042 | 1043 | #### See also 1044 | string.trimLeading 1045 | 1046 | ## string.upper 1047 | #### Syntax 1048 | string.upper (s) returns string 1049 | 1050 | #### What it does 1051 | Converts the string to upper case. 1052 | 1053 | #### Returns 1054 | The upper case version of the string. 1055 | 1056 | #### Example 1057 | `dialog.alert (string.upper ("It's even worse than it appears."))` 1058 | 1059 | #### See also 1060 | string.lower 1061 | 1062 | -------------------------------------------------------------------------------- /markdownapp/source.opml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | nodeEditor: docServerToMarkdown 6 | Wed, 05 Jan 2022 14:48:50 GMT 7 | Thu, 06 Jan 2022 14:15:00 GMT 8 | Dave Winer 9 | http://davewiner.com/ 10 | 1, 2, 3, 10, 27, 31, 36, 38, 39, 40, 48, 58, 65, 67, 69, 70, 72, 73, 74, 83 11 | 40 12 | 88 13 | 899 14 | 1086 15 | 1881 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | --------------------------------------------------------------------------------